blob: 8e453bddd02b1ba3bcf0c431a8e2aa7657e419f8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.text.html;
26
27import java.util.Enumeration;
28import java.awt.*;
29import javax.swing.SizeRequirements;
30import javax.swing.border.*;
31import javax.swing.event.DocumentEvent;
32import javax.swing.text.*;
33
34/**
35 * A view implementation to display a block (as a box)
36 * with CSS specifications.
37 *
38 * @author Timothy Prinzing
39 */
40public class BlockView extends BoxView {
41
42 /**
43 * Creates a new view that represents an
44 * html box. This can be used for a number
45 * of elements.
46 *
47 * @param elem the element to create a view for
48 * @param axis either View.X_AXIS or View.Y_AXIS
49 */
50 public BlockView(Element elem, int axis) {
51 super(elem, axis);
52 }
53
54 /**
55 * Establishes the parent view for this view. This is
56 * guaranteed to be called before any other methods if the
57 * parent view is functioning properly.
58 * <p>
59 * This is implemented
60 * to forward to the superclass as well as call the
61 * {@link #setPropertiesFromAttributes()}
62 * method to set the paragraph properties from the css
63 * attributes. The call is made at this time to ensure
64 * the ability to resolve upward through the parents
65 * view attributes.
66 *
67 * @param parent the new parent, or null if the view is
68 * being removed from a parent it was previously added
69 * to
70 */
71 public void setParent(View parent) {
72 super.setParent(parent);
73 if (parent != null) {
74 setPropertiesFromAttributes();
75 }
76 }
77
78 /**
79 * Calculate the requirements of the block along the major
80 * axis (i.e. the axis along with it tiles). This is implemented
81 * to provide the superclass behavior and then adjust it if the
82 * CSS width or height attribute is specified and applicable to
83 * the axis.
84 */
85 protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
86 if (r == null) {
87 r = new SizeRequirements();
88 }
89 if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
90 r = super.calculateMajorAxisRequirements(axis, r);
91 }
92 else {
93 // Offset by the margins so that pref/min/max return the
94 // right value.
95 SizeRequirements parentR = super.calculateMajorAxisRequirements(
96 axis, null);
97 int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
98 getTopInset() + getBottomInset();
99 r.minimum -= margin;
100 r.preferred -= margin;
101 r.maximum -= margin;
102 constrainSize(axis, r, parentR);
103 }
104 return r;
105 }
106
107 /**
108 * Calculate the requirements of the block along the minor
109 * axis (i.e. the axis orthoginal to the axis along with it tiles).
110 * This is implemented
111 * to provide the superclass behavior and then adjust it if the
112 * CSS width or height attribute is specified and applicable to
113 * the axis.
114 */
115 protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
116 if (r == null) {
117 r = new SizeRequirements();
118 }
119
120 if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
121
122 /*
123 * The requirements were not directly specified by attributes, so
124 * compute the aggregate of the requirements of the children. The
125 * children that have a percentage value specified will be treated
126 * as completely stretchable since that child is not limited in any
127 * way.
128 */
129/*
130 int min = 0;
131 long pref = 0;
132 int max = 0;
133 int n = getViewCount();
134 for (int i = 0; i < n; i++) {
135 View v = getView(i);
136 min = Math.max((int) v.getMinimumSpan(axis), min);
137 pref = Math.max((int) v.getPreferredSpan(axis), pref);
138 if (
139 max = Math.max((int) v.getMaximumSpan(axis), max);
140
141 }
142 r.preferred = (int) pref;
143 r.minimum = min;
144 r.maximum = max;
145 */
146 r = super.calculateMinorAxisRequirements(axis, r);
147 }
148 else {
149 // Offset by the margins so that pref/min/max return the
150 // right value.
151 SizeRequirements parentR = super.calculateMinorAxisRequirements(
152 axis, null);
153 int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
154 getTopInset() + getBottomInset();
155 r.minimum -= margin;
156 r.preferred -= margin;
157 r.maximum -= margin;
158 constrainSize(axis, r, parentR);
159 }
160
161 /*
162 * Set the alignment based upon the CSS properties if it is
163 * specified. For X_AXIS this would be text-align, for
164 * Y_AXIS this would be vertical-align.
165 */
166 if (axis == X_AXIS) {
167 Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
168 if (o != null) {
169 String align = o.toString();
170 if (align.equals("center")) {
171 r.alignment = 0.5f;
172 } else if (align.equals("right")) {
173 r.alignment = 1.0f;
174 } else {
175 r.alignment = 0.0f;
176 }
177 }
178 }
179 // Y_AXIS TBD
180 return r;
181 }
182
183 boolean isPercentage(int axis, AttributeSet a) {
184 if (axis == X_AXIS) {
185 if (cssWidth != null) {
186 return cssWidth.isPercentage();
187 }
188 } else {
189 if (cssHeight != null) {
190 return cssHeight.isPercentage();
191 }
192 }
193 return false;
194 }
195
196 /**
197 * Adjust the given requirements to the CSS width or height if
198 * it is specified along the applicable axis. Return true if the
199 * size is exactly specified, false if the span is not specified
200 * in an attribute or the size specified is a percentage.
201 */
202 static boolean spanSetFromAttributes(int axis, SizeRequirements r,
203 CSS.LengthValue cssWidth,
204 CSS.LengthValue cssHeight) {
205 if (axis == X_AXIS) {
206 if ((cssWidth != null) && (! cssWidth.isPercentage())) {
207 r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
208 return true;
209 }
210 } else {
211 if ((cssHeight != null) && (! cssHeight.isPercentage())) {
212 r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
213 return true;
214 }
215 }
216 return false;
217 }
218
219 /**
220 * Performs layout for the minor axis of the box (i.e. the
221 * axis orthoginal to the axis that it represents). The results
222 * of the layout (the offset and span for each children) are
223 * placed in the given arrays which represent the allocations to
224 * the children along the minor axis.
225 *
226 * @param targetSpan the total span given to the view, which
227 * whould be used to layout the childre.
228 * @param axis the axis being layed out
229 * @param offsets the offsets from the origin of the view for
230 * each of the child views; this is a return value and is
231 * filled in by the implementation of this method
232 * @param spans the span of each child view; this is a return
233 * value and is filled in by the implementation of this method
234 */
235 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
236 int n = getViewCount();
237 Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT;
238 for (int i = 0; i < n; i++) {
239 View v = getView(i);
240 int min = (int) v.getMinimumSpan(axis);
241 int max;
242
243 // check for percentage span
244 AttributeSet a = v.getAttributes();
245 CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
246 if ((lv != null) && lv.isPercentage()) {
247 // bound the span to the percentage specified
248 min = Math.max((int) lv.getValue(targetSpan), min);
249 max = min;
250 } else {
251 max = (int)v.getMaximumSpan(axis);
252 }
253
254 // assign the offset and span for the child
255 if (max < targetSpan) {
256 // can't make the child this wide, align it
257 float align = v.getAlignment(axis);
258 offsets[i] = (int) ((targetSpan - max) * align);
259 spans[i] = max;
260 } else {
261 // make it the target width, or as small as it can get.
262 offsets[i] = 0;
263 spans[i] = Math.max(min, targetSpan);
264 }
265 }
266 }
267
268
269 /**
270 * Renders using the given rendering surface and area on that
271 * surface. This is implemented to delegate to the css box
272 * painter to paint the border and background prior to the
273 * interior.
274 *
275 * @param g the rendering surface to use
276 * @param allocation the allocated region to render into
277 * @see View#paint
278 */
279 public void paint(Graphics g, Shape allocation) {
280 Rectangle a = (Rectangle) allocation;
281 painter.paint(g, a.x, a.y, a.width, a.height, this);
282 super.paint(g, a);
283 }
284
285 /**
286 * Fetches the attributes to use when rendering. This is
287 * implemented to multiplex the attributes specified in the
288 * model with a StyleSheet.
289 */
290 public AttributeSet getAttributes() {
291 if (attr == null) {
292 StyleSheet sheet = getStyleSheet();
293 attr = sheet.getViewAttributes(this);
294 }
295 return attr;
296 }
297
298 /**
299 * Gets the resize weight.
300 *
301 * @param axis may be either X_AXIS or Y_AXIS
302 * @return the weight
303 * @exception IllegalArgumentException for an invalid axis
304 */
305 public int getResizeWeight(int axis) {
306 switch (axis) {
307 case View.X_AXIS:
308 return 1;
309 case View.Y_AXIS:
310 return 0;
311 default:
312 throw new IllegalArgumentException("Invalid axis: " + axis);
313 }
314 }
315
316 /**
317 * Gets the alignment.
318 *
319 * @param axis may be either X_AXIS or Y_AXIS
320 * @return the alignment
321 */
322 public float getAlignment(int axis) {
323 switch (axis) {
324 case View.X_AXIS:
325 return 0;
326 case View.Y_AXIS:
327 if (getViewCount() == 0) {
328 return 0;
329 }
330 float span = getPreferredSpan(View.Y_AXIS);
331 View v = getView(0);
332 float above = v.getPreferredSpan(View.Y_AXIS);
333 float a = (((int)span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span: 0;
334 return a;
335 default:
336 throw new IllegalArgumentException("Invalid axis: " + axis);
337 }
338 }
339
340 public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
341 super.changedUpdate(changes, a, f);
342 int pos = changes.getOffset();
343 if (pos <= getStartOffset() && (pos + changes.getLength()) >=
344 getEndOffset()) {
345 setPropertiesFromAttributes();
346 }
347 }
348
349 /**
350 * Determines the preferred span for this view along an
351 * axis.
352 *
353 * @param axis may be either <code>View.X_AXIS</code>
354 * or <code>View.Y_AXIS</code>
355 * @return the span the view would like to be rendered into >= 0;
356 * typically the view is told to render into the span
357 * that is returned, although there is no guarantee;
358 * the parent may choose to resize or break the view
359 * @exception IllegalArgumentException for an invalid axis type
360 */
361 public float getPreferredSpan(int axis) {
362 return super.getPreferredSpan(axis);
363 }
364
365 /**
366 * Determines the minimum span for this view along an
367 * axis.
368 *
369 * @param axis may be either <code>View.X_AXIS</code>
370 * or <code>View.Y_AXIS</code>
371 * @return the span the view would like to be rendered into >= 0;
372 * typically the view is told to render into the span
373 * that is returned, although there is no guarantee;
374 * the parent may choose to resize or break the view
375 * @exception IllegalArgumentException for an invalid axis type
376 */
377 public float getMinimumSpan(int axis) {
378 return super.getMinimumSpan(axis);
379 }
380
381 /**
382 * Determines the maximum span for this view along an
383 * axis.
384 *
385 * @param axis may be either <code>View.X_AXIS</code>
386 * or <code>View.Y_AXIS</code>
387 * @return the span the view would like to be rendered into >= 0;
388 * typically the view is told to render into the span
389 * that is returned, although there is no guarantee;
390 * the parent may choose to resize or break the view
391 * @exception IllegalArgumentException for an invalid axis type
392 */
393 public float getMaximumSpan(int axis) {
394 return super.getMaximumSpan(axis);
395 }
396
397 /**
398 * Update any cached values that come from attributes.
399 */
400 protected void setPropertiesFromAttributes() {
401
402 // update attributes
403 StyleSheet sheet = getStyleSheet();
404 attr = sheet.getViewAttributes(this);
405
406 // Reset the painter
407 painter = sheet.getBoxPainter(attr);
408 if (attr != null) {
409 setInsets((short) painter.getInset(TOP, this),
410 (short) painter.getInset(LEFT, this),
411 (short) painter.getInset(BOTTOM, this),
412 (short) painter.getInset(RIGHT, this));
413 }
414
415 // Get the width/height
416 cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
417 cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
418 }
419
420 protected StyleSheet getStyleSheet() {
421 HTMLDocument doc = (HTMLDocument) getDocument();
422 return doc.getStyleSheet();
423 }
424
425 /**
426 * Constrains <code>want</code> to fit in the minimum size specified
427 * by <code>min</code>.
428 */
429 private void constrainSize(int axis, SizeRequirements want,
430 SizeRequirements min) {
431 if (min.minimum > want.minimum) {
432 want.minimum = want.preferred = min.minimum;
433 want.maximum = Math.max(want.maximum, min.maximum);
434 }
435 }
436
437 private AttributeSet attr;
438 private StyleSheet.BoxPainter painter;
439
440 private CSS.LengthValue cssWidth;
441 private CSS.LengthValue cssHeight;
442
443}