0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing.text.html;
0N/A
0N/Aimport java.util.Enumeration;
0N/Aimport java.awt.*;
0N/Aimport javax.swing.SizeRequirements;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.event.DocumentEvent;
0N/Aimport javax.swing.text.*;
0N/A
0N/A/**
0N/A * A view implementation to display a block (as a box)
0N/A * with CSS specifications.
0N/A *
0N/A * @author Timothy Prinzing
0N/A */
0N/Apublic class BlockView extends BoxView {
0N/A
0N/A /**
0N/A * Creates a new view that represents an
0N/A * html box. This can be used for a number
0N/A * of elements.
0N/A *
0N/A * @param elem the element to create a view for
0N/A * @param axis either View.X_AXIS or View.Y_AXIS
0N/A */
0N/A public BlockView(Element elem, int axis) {
0N/A super(elem, axis);
0N/A }
0N/A
0N/A /**
0N/A * Establishes the parent view for this view. This is
0N/A * guaranteed to be called before any other methods if the
0N/A * parent view is functioning properly.
0N/A * <p>
0N/A * This is implemented
0N/A * to forward to the superclass as well as call the
0N/A * {@link #setPropertiesFromAttributes()}
0N/A * method to set the paragraph properties from the css
0N/A * attributes. The call is made at this time to ensure
0N/A * the ability to resolve upward through the parents
0N/A * view attributes.
0N/A *
0N/A * @param parent the new parent, or null if the view is
0N/A * being removed from a parent it was previously added
0N/A * to
0N/A */
0N/A public void setParent(View parent) {
0N/A super.setParent(parent);
0N/A if (parent != null) {
0N/A setPropertiesFromAttributes();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Calculate the requirements of the block along the major
0N/A * axis (i.e. the axis along with it tiles). This is implemented
0N/A * to provide the superclass behavior and then adjust it if the
0N/A * CSS width or height attribute is specified and applicable to
0N/A * the axis.
0N/A */
0N/A protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
0N/A if (r == null) {
0N/A r = new SizeRequirements();
0N/A }
0N/A if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
0N/A r = super.calculateMajorAxisRequirements(axis, r);
0N/A }
0N/A else {
0N/A // Offset by the margins so that pref/min/max return the
0N/A // right value.
0N/A SizeRequirements parentR = super.calculateMajorAxisRequirements(
0N/A axis, null);
0N/A int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
0N/A getTopInset() + getBottomInset();
0N/A r.minimum -= margin;
0N/A r.preferred -= margin;
0N/A r.maximum -= margin;
0N/A constrainSize(axis, r, parentR);
0N/A }
0N/A return r;
0N/A }
0N/A
0N/A /**
0N/A * Calculate the requirements of the block along the minor
0N/A * axis (i.e. the axis orthoginal to the axis along with it tiles).
0N/A * This is implemented
0N/A * to provide the superclass behavior and then adjust it if the
0N/A * CSS width or height attribute is specified and applicable to
0N/A * the axis.
0N/A */
0N/A protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
0N/A if (r == null) {
0N/A r = new SizeRequirements();
0N/A }
0N/A
0N/A if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
0N/A
0N/A /*
0N/A * The requirements were not directly specified by attributes, so
0N/A * compute the aggregate of the requirements of the children. The
0N/A * children that have a percentage value specified will be treated
0N/A * as completely stretchable since that child is not limited in any
0N/A * way.
0N/A */
0N/A/*
0N/A int min = 0;
0N/A long pref = 0;
0N/A int max = 0;
0N/A int n = getViewCount();
0N/A for (int i = 0; i < n; i++) {
0N/A View v = getView(i);
0N/A min = Math.max((int) v.getMinimumSpan(axis), min);
0N/A pref = Math.max((int) v.getPreferredSpan(axis), pref);
0N/A if (
0N/A max = Math.max((int) v.getMaximumSpan(axis), max);
0N/A
0N/A }
0N/A r.preferred = (int) pref;
0N/A r.minimum = min;
0N/A r.maximum = max;
0N/A */
0N/A r = super.calculateMinorAxisRequirements(axis, r);
0N/A }
0N/A else {
0N/A // Offset by the margins so that pref/min/max return the
0N/A // right value.
0N/A SizeRequirements parentR = super.calculateMinorAxisRequirements(
0N/A axis, null);
0N/A int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
0N/A getTopInset() + getBottomInset();
0N/A r.minimum -= margin;
0N/A r.preferred -= margin;
0N/A r.maximum -= margin;
0N/A constrainSize(axis, r, parentR);
0N/A }
0N/A
0N/A /*
0N/A * Set the alignment based upon the CSS properties if it is
0N/A * specified. For X_AXIS this would be text-align, for
0N/A * Y_AXIS this would be vertical-align.
0N/A */
0N/A if (axis == X_AXIS) {
0N/A Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
0N/A if (o != null) {
0N/A String align = o.toString();
0N/A if (align.equals("center")) {
0N/A r.alignment = 0.5f;
0N/A } else if (align.equals("right")) {
0N/A r.alignment = 1.0f;
0N/A } else {
0N/A r.alignment = 0.0f;
0N/A }
0N/A }
0N/A }
0N/A // Y_AXIS TBD
0N/A return r;
0N/A }
0N/A
0N/A boolean isPercentage(int axis, AttributeSet a) {
0N/A if (axis == X_AXIS) {
0N/A if (cssWidth != null) {
0N/A return cssWidth.isPercentage();
0N/A }
0N/A } else {
0N/A if (cssHeight != null) {
0N/A return cssHeight.isPercentage();
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Adjust the given requirements to the CSS width or height if
0N/A * it is specified along the applicable axis. Return true if the
0N/A * size is exactly specified, false if the span is not specified
0N/A * in an attribute or the size specified is a percentage.
0N/A */
0N/A static boolean spanSetFromAttributes(int axis, SizeRequirements r,
0N/A CSS.LengthValue cssWidth,
0N/A CSS.LengthValue cssHeight) {
0N/A if (axis == X_AXIS) {
0N/A if ((cssWidth != null) && (! cssWidth.isPercentage())) {
0N/A r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
0N/A return true;
0N/A }
0N/A } else {
0N/A if ((cssHeight != null) && (! cssHeight.isPercentage())) {
0N/A r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
0N/A return true;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Performs layout for the minor axis of the box (i.e. the
0N/A * axis orthoginal to the axis that it represents). The results
0N/A * of the layout (the offset and span for each children) are
0N/A * placed in the given arrays which represent the allocations to
0N/A * the children along the minor axis.
0N/A *
0N/A * @param targetSpan the total span given to the view, which
0N/A * whould be used to layout the childre.
0N/A * @param axis the axis being layed out
0N/A * @param offsets the offsets from the origin of the view for
0N/A * each of the child views; this is a return value and is
0N/A * filled in by the implementation of this method
0N/A * @param spans the span of each child view; this is a return
0N/A * value and is filled in by the implementation of this method
0N/A */
0N/A protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
0N/A int n = getViewCount();
0N/A Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT;
0N/A for (int i = 0; i < n; i++) {
0N/A View v = getView(i);
0N/A int min = (int) v.getMinimumSpan(axis);
0N/A int max;
0N/A
0N/A // check for percentage span
0N/A AttributeSet a = v.getAttributes();
0N/A CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
0N/A if ((lv != null) && lv.isPercentage()) {
0N/A // bound the span to the percentage specified
0N/A min = Math.max((int) lv.getValue(targetSpan), min);
0N/A max = min;
0N/A } else {
0N/A max = (int)v.getMaximumSpan(axis);
0N/A }
0N/A
0N/A // assign the offset and span for the child
0N/A if (max < targetSpan) {
0N/A // can't make the child this wide, align it
0N/A float align = v.getAlignment(axis);
0N/A offsets[i] = (int) ((targetSpan - max) * align);
0N/A spans[i] = max;
0N/A } else {
0N/A // make it the target width, or as small as it can get.
0N/A offsets[i] = 0;
0N/A spans[i] = Math.max(min, targetSpan);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Renders using the given rendering surface and area on that
0N/A * surface. This is implemented to delegate to the css box
0N/A * painter to paint the border and background prior to the
0N/A * interior.
0N/A *
0N/A * @param g the rendering surface to use
0N/A * @param allocation the allocated region to render into
0N/A * @see View#paint
0N/A */
0N/A public void paint(Graphics g, Shape allocation) {
0N/A Rectangle a = (Rectangle) allocation;
0N/A painter.paint(g, a.x, a.y, a.width, a.height, this);
0N/A super.paint(g, a);
0N/A }
0N/A
0N/A /**
0N/A * Fetches the attributes to use when rendering. This is
0N/A * implemented to multiplex the attributes specified in the
0N/A * model with a StyleSheet.
0N/A */
0N/A public AttributeSet getAttributes() {
0N/A if (attr == null) {
0N/A StyleSheet sheet = getStyleSheet();
0N/A attr = sheet.getViewAttributes(this);
0N/A }
0N/A return attr;
0N/A }
0N/A
0N/A /**
0N/A * Gets the resize weight.
0N/A *
0N/A * @param axis may be either X_AXIS or Y_AXIS
0N/A * @return the weight
0N/A * @exception IllegalArgumentException for an invalid axis
0N/A */
0N/A public int getResizeWeight(int axis) {
0N/A switch (axis) {
0N/A case View.X_AXIS:
0N/A return 1;
0N/A case View.Y_AXIS:
0N/A return 0;
0N/A default:
0N/A throw new IllegalArgumentException("Invalid axis: " + axis);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets the alignment.
0N/A *
0N/A * @param axis may be either X_AXIS or Y_AXIS
0N/A * @return the alignment
0N/A */
0N/A public float getAlignment(int axis) {
0N/A switch (axis) {
0N/A case View.X_AXIS:
0N/A return 0;
0N/A case View.Y_AXIS:
0N/A if (getViewCount() == 0) {
0N/A return 0;
0N/A }
0N/A float span = getPreferredSpan(View.Y_AXIS);
0N/A View v = getView(0);
0N/A float above = v.getPreferredSpan(View.Y_AXIS);
0N/A float a = (((int)span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span: 0;
0N/A return a;
0N/A default:
0N/A throw new IllegalArgumentException("Invalid axis: " + axis);
0N/A }
0N/A }
0N/A
0N/A public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
0N/A super.changedUpdate(changes, a, f);
0N/A int pos = changes.getOffset();
0N/A if (pos <= getStartOffset() && (pos + changes.getLength()) >=
0N/A getEndOffset()) {
0N/A setPropertiesFromAttributes();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Determines the preferred span for this view along an
0N/A * axis.
0N/A *
0N/A * @param axis may be either <code>View.X_AXIS</code>
0N/A * or <code>View.Y_AXIS</code>
0N/A * @return the span the view would like to be rendered into >= 0;
0N/A * typically the view is told to render into the span
0N/A * that is returned, although there is no guarantee;
0N/A * the parent may choose to resize or break the view
0N/A * @exception IllegalArgumentException for an invalid axis type
0N/A */
0N/A public float getPreferredSpan(int axis) {
0N/A return super.getPreferredSpan(axis);
0N/A }
0N/A
0N/A /**
0N/A * Determines the minimum span for this view along an
0N/A * axis.
0N/A *
0N/A * @param axis may be either <code>View.X_AXIS</code>
0N/A * or <code>View.Y_AXIS</code>
0N/A * @return the span the view would like to be rendered into >= 0;
0N/A * typically the view is told to render into the span
0N/A * that is returned, although there is no guarantee;
0N/A * the parent may choose to resize or break the view
0N/A * @exception IllegalArgumentException for an invalid axis type
0N/A */
0N/A public float getMinimumSpan(int axis) {
0N/A return super.getMinimumSpan(axis);
0N/A }
0N/A
0N/A /**
0N/A * Determines the maximum span for this view along an
0N/A * axis.
0N/A *
0N/A * @param axis may be either <code>View.X_AXIS</code>
0N/A * or <code>View.Y_AXIS</code>
0N/A * @return the span the view would like to be rendered into >= 0;
0N/A * typically the view is told to render into the span
0N/A * that is returned, although there is no guarantee;
0N/A * the parent may choose to resize or break the view
0N/A * @exception IllegalArgumentException for an invalid axis type
0N/A */
0N/A public float getMaximumSpan(int axis) {
0N/A return super.getMaximumSpan(axis);
0N/A }
0N/A
0N/A /**
0N/A * Update any cached values that come from attributes.
0N/A */
0N/A protected void setPropertiesFromAttributes() {
0N/A
0N/A // update attributes
0N/A StyleSheet sheet = getStyleSheet();
0N/A attr = sheet.getViewAttributes(this);
0N/A
0N/A // Reset the painter
0N/A painter = sheet.getBoxPainter(attr);
0N/A if (attr != null) {
0N/A setInsets((short) painter.getInset(TOP, this),
0N/A (short) painter.getInset(LEFT, this),
0N/A (short) painter.getInset(BOTTOM, this),
0N/A (short) painter.getInset(RIGHT, this));
0N/A }
0N/A
0N/A // Get the width/height
0N/A cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
0N/A cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
0N/A }
0N/A
0N/A protected StyleSheet getStyleSheet() {
0N/A HTMLDocument doc = (HTMLDocument) getDocument();
0N/A return doc.getStyleSheet();
0N/A }
0N/A
0N/A /**
0N/A * Constrains <code>want</code> to fit in the minimum size specified
0N/A * by <code>min</code>.
0N/A */
0N/A private void constrainSize(int axis, SizeRequirements want,
0N/A SizeRequirements min) {
0N/A if (min.minimum > want.minimum) {
0N/A want.minimum = want.preferred = min.minimum;
0N/A want.maximum = Math.max(want.maximum, min.maximum);
0N/A }
0N/A }
0N/A
0N/A private AttributeSet attr;
0N/A private StyleSheet.BoxPainter painter;
0N/A
0N/A private CSS.LengthValue cssWidth;
0N/A private CSS.LengthValue cssHeight;
0N/A
0N/A}