/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing.text; import java.io.PrintStream;import java.util.Vector;import java.awt.*;import javax.swing.event.DocumentEvent;import javax.swing.SizeRequirements; /** * A view that arranges its children into a box shape by tiling * its children along an axis. The box is somewhat like that * found in TeX where there is alignment of the * children, flexibility of the children is considered, etc. * This is a building block that might be useful to represent * things like a collection of lines, paragraphs, * lists, columns, pages, etc. The axis along which the children are tiled is * considered the major axis. The orthoginal axis is the minor axis. * <p> * Layout for each axis is handled separately by the methods * <code>layoutMajorAxis</code> and <code>layoutMinorAxis</code>. * Subclasses can change the layout algorithm by * reimplementing these methods. These methods will be called * as necessary depending upon whether or not there is cached * layout information and the cache is considered * valid. These methods are typically called if the given size * along the axis changes, or if <code>layoutChanged</code> is * called to force an updated layout. The <code>layoutChanged</code> * method invalidates cached layout information, if there is any. * The requirements published to the parent view are calculated by * the methods <code>calculateMajorAxisRequirements</code> * and <code>calculateMinorAxisRequirements</code>. * If the layout algorithm is changed, these methods will * likely need to be reimplemented. * * @author Timothy Prinzing */public class BoxView extends CompositeView { /** * Constructs a <code>BoxView</code>. * * @param elem the element this view is responsible for * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> */ public BoxView(Element elem, int axis) { super(elem); tempRect = new Rectangle(); this.majorAxis = axis; majorOffsets = new int[0]; majorSpans = new int[0]; majorReqValid = false; majorAllocValid = false; minorOffsets = new int[0]; minorSpans = new int[0]; minorReqValid = false; minorAllocValid = false; } /** * Fetches the tile axis property. This is the axis along which * the child views are tiled. * * @return the major axis of the box, either * <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public int getAxis() { return majorAxis; } /** * Sets the tile axis property. This is the axis along which * the child views are tiled. * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public void setAxis(int axis) { boolean axisChanged = (axis != majorAxis); majorAxis = axis; if (axisChanged) { preferenceChanged(null, true, true); } } /** * Invalidates the layout along an axis. This happens * automatically if the preferences have changed for * any of the child views. In some cases the layout * may need to be recalculated when the preferences * have not changed. The layout can be marked as * invalid by calling this method. The layout will * be updated the next time the <code>setSize</code> method * is called on this view (typically in paint). * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public void layoutChanged(int axis) { if (axis == majorAxis) { majorAllocValid = false; } else { minorAllocValid = false; } } /** * Determines if the layout is valid along the given axis. * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.4 */ protected boolean isLayoutValid(int axis) { if (axis == majorAxis) { return majorAllocValid; } else { return minorAllocValid; } } /** * Paints a child. By default * that is all it does, but a subclass can use this to paint * things relative to the child. * * @param g the graphics context * @param alloc the allocated region to paint into * @param index the child index, >= 0 && < getViewCount() */ protected void paintChild(Graphics g, Rectangle alloc, int index) { View child = getView(index); child.paint(g, alloc); } // --- View methods --------------------------------------------- /** * Invalidates the layout and resizes the cache of * requests/allocations. The child allocations can still * be accessed for the old layout, but the new children * will have an offset and span of 0. * * @param index the starting index into the child views to insert * the new views; this should be a value >= 0 and <= getViewCount * @param length the number of existing child views to remove; * This should be a value >= 0 and <= (getViewCount() - offset) * @param elems the child views to add; this value can be * <code>null</code>to indicate no children are being added * (useful to remove) */ public void replace(int index, int length, View[] elems) { super.replace(index, length, elems); // invalidate cache int nInserted = (elems != null) ? elems.length : 0; majorOffsets = updateLayoutArray(majorOffsets, index, nInserted); majorSpans = updateLayoutArray(majorSpans, index, nInserted); majorReqValid = false; majorAllocValid = false; minorOffsets = updateLayoutArray(minorOffsets, index, nInserted); minorSpans = updateLayoutArray(minorSpans, index, nInserted); minorReqValid = false; minorAllocValid = false; } /** * Resizes the given layout array to match the new number of * child views. The current number of child views are used to * produce the new array. The contents of the old array are * inserted into the new array at the appropriate places so that * the old layout information is transferred to the new array. * * @param oldArray the original layout array * @param offset location where new views will be inserted * @param nInserted the number of child views being inserted; * therefore the number of blank spaces to leave in the * new array at location <code>offset</code> * @return the new layout array */ int[] updateLayoutArray(int[] oldArray, int offset, int nInserted) { int n = getViewCount(); int[] newArray = new int[n]; System.arraycopy(oldArray, 0, newArray, 0, offset); System.arraycopy(oldArray, offset, newArray, offset + nInserted, n - nInserted - offset); return newArray; } /** * Forwards the given <code>DocumentEvent</code> to the child views * that need to be notified of the change to the model. * If a child changed its requirements and the allocation * was valid prior to forwarding the portion of the box * from the starting child to the end of the box will * be repainted. * * @param ec changes to the element this view is responsible * for (may be <code>null</code> if there were no changes) * @param e the change information from the associated document * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see #insertUpdate * @see #removeUpdate * @see #changedUpdate * @since 1.3 */ protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { boolean wasValid = isLayoutValid(majorAxis); super.forwardUpdate(ec, e, a, f); // determine if a repaint is needed if (wasValid && (! isLayoutValid(majorAxis))) { // Repaint is needed because one of the tiled children // have changed their span along the major axis. If there // is a hosting component and an allocated shape we repaint. Component c = getContainer(); if ((a != null) && (c != null)) { int pos = e.getOffset(); int index = getViewIndexAtPosition(pos); Rectangle alloc = getInsideAllocation(a); if (majorAxis == X_AXIS) { alloc.x += majorOffsets[index]; alloc.width -= majorOffsets[index]; } else { alloc.y += minorOffsets[index]; alloc.height -= minorOffsets[index]; } c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); } } } /** * This is called by a child to indicate its * preferred span has changed. This is implemented to * throw away cached layout information so that new * calculations will be done the next time the children * need an allocation. * * @param child the child view * @param width true if the width preference should change * @param height true if the height preference should change */ public void preferenceChanged(View child, boolean width, boolean height) { boolean majorChanged = (majorAxis == X_AXIS) ? width : height; boolean minorChanged = (majorAxis == X_AXIS) ? height : width; if (majorChanged) { majorReqValid = false; majorAllocValid = false; } if (minorChanged) { minorReqValid = false; minorAllocValid = false; } super.preferenceChanged(child, width, height); } /** * Gets the resize weight. A value of 0 or less is not resizable. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the weight * @exception IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { checkRequests(axis); if (axis == majorAxis) { if ((majorRequest.preferred != majorRequest.minimum) || (majorRequest.preferred != majorRequest.maximum)) { return 1; } } else { if ((minorRequest.preferred != minorRequest.minimum) || (minorRequest.preferred != minorRequest.maximum)) { return 1; } } return 0; } /** * Sets the size of the view along an axis. This should cause * layout of the view along the given axis. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @param span the span to layout to >= 0 */ void setSpanOnAxis(int axis, float span) { if (axis == majorAxis) { if (majorSpan != (int) span) { majorAllocValid = false; } if (! majorAllocValid) { // layout the major axis majorSpan = (int) span; checkRequests(majorAxis); layoutMajorAxis(majorSpan, axis, majorOffsets, majorSpans); majorAllocValid = true; // flush changes to the children updateChildSizes(); } } else { if (((int) span) != minorSpan) { minorAllocValid = false; } if (! minorAllocValid) { // layout the minor axis minorSpan = (int) span; checkRequests(axis); layoutMinorAxis(minorSpan, axis, minorOffsets, minorSpans); minorAllocValid = true; // flush changes to the children updateChildSizes(); } } } /** * Propagates the current allocations to the child views. */ void updateChildSizes() { int n = getViewCount(); if (majorAxis == X_AXIS) { for (int i = 0; i < n; i++) { View v = getView(i); v.setSize((float) majorSpans[i], (float) minorSpans[i]); } } else { for (int i = 0; i < n; i++) { View v = getView(i); v.setSize((float) minorSpans[i], (float) majorSpans[i]); } } } /** * Returns the size of the view along an axis. This is implemented * to return zero. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the current span of the view along the given axis, >= 0 */ float getSpanOnAxis(int axis) { if (axis == majorAxis) { return majorSpan; } else { return minorSpan; } } /** * Sets the size of the view. This should cause * layout of the view if the view caches any layout * information. This is implemented to call the * layout method with the sizes inside of the insets. * * @param width the width >= 0 * @param height the height >= 0 */ public void setSize(float width, float height) { layout(Math.max(0, (int)(width - getLeftInset() - getRightInset())), Math.max(0, (int)(height - getTopInset() - getBottomInset()))); } /** * Renders the <code>BoxView</code> using the given * rendering surface and area * on that surface. Only the children that intersect * the clip bounds of the given <code>Graphics</code> * will be rendered. * * @param g the rendering surface to use * @param allocation the allocated region to render into * @see View#paint */ public void paint(Graphics g, Shape allocation) { Rectangle alloc = (allocation instanceof Rectangle) ? (Rectangle)allocation : allocation.getBounds(); int n = getViewCount(); int x = alloc.x + getLeftInset(); int y = alloc.y + getTopInset(); Rectangle clip = g.getClipBounds(); for (int i = 0; i < n; i++) { tempRect.x = x + getOffset(X_AXIS, i); tempRect.y = y + getOffset(Y_AXIS, i); tempRect.width = getSpan(X_AXIS, i); tempRect.height = getSpan(Y_AXIS, i); int trx0 = tempRect.x, trx1 = trx0 + tempRect.width; int try0 = tempRect.y, try1 = try0 + tempRect.height; int crx0 = clip.x, crx1 = crx0 + clip.width; int cry0 = clip.y, cry1 = cry0 + clip.height; // We should paint views that intersect with clipping region // even if the intersection has no inside points (is a line). // This is needed for supporting views that have zero width, like // views that contain only combining marks. if ((trx1 >= crx0) && (try1 >= cry0) && (crx1 >= trx0) && (cry1 >= try0)) { paintChild(g, tempRect, i); } } } /** * Fetches the allocation for the given child view. * This enables finding out where various views * are located. This is implemented to return * <code>null</code> if the layout is invalid, * otherwise the superclass behavior is executed. * * @param index the index of the child, >= 0 && < getViewCount() * @param a the allocation to this view * @return the allocation to the child; or <code>null</code> * if <code>a</code> is <code>null</code>; * or <code>null</code> if the layout is invalid */ public Shape getChildAllocation(int index, Shape a) { if (a != null) { Shape ca = super.getChildAllocation(index, a); if ((ca != null) && (! isAllocationValid())) { // The child allocation may not have been set yet. Rectangle r = (ca instanceof Rectangle) ? (Rectangle) ca : ca.getBounds(); if ((r.width == 0) && (r.height == 0)) { return null; } } return ca; } return null; } /** * Provides a mapping from the document model coordinate space * to the coordinate space of the view mapped to it. This makes * sure the allocation is valid before calling the superclass. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position * @exception BadLocationException if the given position does * not represent a valid location in the associated document * @see View#modelToView */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { if (! isAllocationValid()) { Rectangle alloc = a.getBounds(); setSize(alloc.width, alloc.height); } return super.modelToView(pos, a, b); } /** * Provides a mapping from the view coordinate space to the logical * coordinate space of the model. * * @param x x coordinate of the view location to convert >= 0 * @param y y coordinate of the view location to convert >= 0 * @param a the allocated region to render into * @return the location within the model that best represents the * given point in the view >= 0 * @see View#viewToModel */ public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { if (! isAllocationValid()) { Rectangle alloc = a.getBounds();Lines 1–500 of 1188. Load more
/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing.text; import java.io.PrintStream; import java.util.Vector; import java.awt.*; import javax.swing.event.DocumentEvent; import javax.swing.SizeRequirements; /** * A view that arranges its children into a box shape by tiling * its children along an axis. The box is somewhat like that * found in TeX where there is alignment of the * children, flexibility of the children is considered, etc. * This is a building block that might be useful to represent * things like a collection of lines, paragraphs, * lists, columns, pages, etc. The axis along which the children are tiled is * considered the major axis. The orthoginal axis is the minor axis. * <p> * Layout for each axis is handled separately by the methods * <code>layoutMajorAxis</code> and <code>layoutMinorAxis</code>. * Subclasses can change the layout algorithm by * reimplementing these methods. These methods will be called * as necessary depending upon whether or not there is cached * layout information and the cache is considered * valid. These methods are typically called if the given size * along the axis changes, or if <code>layoutChanged</code> is * called to force an updated layout. The <code>layoutChanged</code> * method invalidates cached layout information, if there is any. * The requirements published to the parent view are calculated by * the methods <code>calculateMajorAxisRequirements</code> * and <code>calculateMinorAxisRequirements</code>. * If the layout algorithm is changed, these methods will * likely need to be reimplemented. * * @author Timothy Prinzing */ public class BoxView extends CompositeView { /** * Constructs a <code>BoxView</code>. * * @param elem the element this view is responsible for * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> */ public BoxView(Element elem, int axis) { super(elem); tempRect = new Rectangle(); this.majorAxis = axis; majorOffsets = new int[0]; majorSpans = new int[0]; majorReqValid = false; majorAllocValid = false; minorOffsets = new int[0]; minorSpans = new int[0]; minorReqValid = false; minorAllocValid = false; } /** * Fetches the tile axis property. This is the axis along which * the child views are tiled. * * @return the major axis of the box, either * <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public int getAxis() { return majorAxis; } /** * Sets the tile axis property. This is the axis along which * the child views are tiled. * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public void setAxis(int axis) { boolean axisChanged = (axis != majorAxis); majorAxis = axis; if (axisChanged) { preferenceChanged(null, true, true); } } /** * Invalidates the layout along an axis. This happens * automatically if the preferences have changed for * any of the child views. In some cases the layout * may need to be recalculated when the preferences * have not changed. The layout can be marked as * invalid by calling this method. The layout will * be updated the next time the <code>setSize</code> method * is called on this view (typically in paint). * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.3 */ public void layoutChanged(int axis) { if (axis == majorAxis) { majorAllocValid = false; } else { minorAllocValid = false; } } /** * Determines if the layout is valid along the given axis. * * @param axis either <code>View.X_AXIS</code> or <code>View.Y_AXIS</code> * * @since 1.4 */ protected boolean isLayoutValid(int axis) { if (axis == majorAxis) { return majorAllocValid; } else { return minorAllocValid; } } /** * Paints a child. By default * that is all it does, but a subclass can use this to paint * things relative to the child. * * @param g the graphics context * @param alloc the allocated region to paint into * @param index the child index, >= 0 && < getViewCount() */ protected void paintChild(Graphics g, Rectangle alloc, int index) { View child = getView(index); child.paint(g, alloc); } // --- View methods --------------------------------------------- /** * Invalidates the layout and resizes the cache of * requests/allocations. The child allocations can still * be accessed for the old layout, but the new children * will have an offset and span of 0. * * @param index the starting index into the child views to insert * the new views; this should be a value >= 0 and <= getViewCount * @param length the number of existing child views to remove; * This should be a value >= 0 and <= (getViewCount() - offset) * @param elems the child views to add; this value can be * <code>null</code>to indicate no children are being added * (useful to remove) */ public void replace(int index, int length, View[] elems) { super.replace(index, length, elems); // invalidate cache int nInserted = (elems != null) ? elems.length : 0; majorOffsets = updateLayoutArray(majorOffsets, index, nInserted); majorSpans = updateLayoutArray(majorSpans, index, nInserted); majorReqValid = false; majorAllocValid = false; minorOffsets = updateLayoutArray(minorOffsets, index, nInserted); minorSpans = updateLayoutArray(minorSpans, index, nInserted); minorReqValid = false; minorAllocValid = false; } /** * Resizes the given layout array to match the new number of * child views. The current number of child views are used to * produce the new array. The contents of the old array are * inserted into the new array at the appropriate places so that * the old layout information is transferred to the new array. * * @param oldArray the original layout array * @param offset location where new views will be inserted * @param nInserted the number of child views being inserted; * therefore the number of blank spaces to leave in the * new array at location <code>offset</code> * @return the new layout array */ int[] updateLayoutArray(int[] oldArray, int offset, int nInserted) { int n = getViewCount(); int[] newArray = new int[n]; System.arraycopy(oldArray, 0, newArray, 0, offset); System.arraycopy(oldArray, offset, newArray, offset + nInserted, n - nInserted - offset); return newArray; } /** * Forwards the given <code>DocumentEvent</code> to the child views * that need to be notified of the change to the model. * If a child changed its requirements and the allocation * was valid prior to forwarding the portion of the box * from the starting child to the end of the box will * be repainted. * * @param ec changes to the element this view is responsible * for (may be <code>null</code> if there were no changes) * @param e the change information from the associated document * @param a the current allocation of the view * @param f the factory to use to rebuild if the view has children * @see #insertUpdate * @see #removeUpdate * @see #changedUpdate * @since 1.3 */ protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, Shape a, ViewFactory f) { boolean wasValid = isLayoutValid(majorAxis); super.forwardUpdate(ec, e, a, f); // determine if a repaint is needed if (wasValid && (! isLayoutValid(majorAxis))) { // Repaint is needed because one of the tiled children // have changed their span along the major axis. If there // is a hosting component and an allocated shape we repaint. Component c = getContainer(); if ((a != null) && (c != null)) { int pos = e.getOffset(); int index = getViewIndexAtPosition(pos); Rectangle alloc = getInsideAllocation(a); if (majorAxis == X_AXIS) { alloc.x += majorOffsets[index]; alloc.width -= majorOffsets[index]; } else { alloc.y += minorOffsets[index]; alloc.height -= minorOffsets[index]; } c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); } } } /** * This is called by a child to indicate its * preferred span has changed. This is implemented to * throw away cached layout information so that new * calculations will be done the next time the children * need an allocation. * * @param child the child view * @param width true if the width preference should change * @param height true if the height preference should change */ public void preferenceChanged(View child, boolean width, boolean height) { boolean majorChanged = (majorAxis == X_AXIS) ? width : height; boolean minorChanged = (majorAxis == X_AXIS) ? height : width; if (majorChanged) { majorReqValid = false; majorAllocValid = false; } if (minorChanged) { minorReqValid = false; minorAllocValid = false; } super.preferenceChanged(child, width, height); } /** * Gets the resize weight. A value of 0 or less is not resizable. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the weight * @exception IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { checkRequests(axis); if (axis == majorAxis) { if ((majorRequest.preferred != majorRequest.minimum) || (majorRequest.preferred != majorRequest.maximum)) { return 1; } } else { if ((minorRequest.preferred != minorRequest.minimum) || (minorRequest.preferred != minorRequest.maximum)) { return 1; } } return 0; } /** * Sets the size of the view along an axis. This should cause * layout of the view along the given axis. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @param span the span to layout to >= 0 */ void setSpanOnAxis(int axis, float span) { if (axis == majorAxis) { if (majorSpan != (int) span) { majorAllocValid = false; } if (! majorAllocValid) { // layout the major axis majorSpan = (int) span; checkRequests(majorAxis); layoutMajorAxis(majorSpan, axis, majorOffsets, majorSpans); majorAllocValid = true; // flush changes to the children updateChildSizes(); } } else { if (((int) span) != minorSpan) { minorAllocValid = false; } if (! minorAllocValid) { // layout the minor axis minorSpan = (int) span; checkRequests(axis); layoutMinorAxis(minorSpan, axis, minorOffsets, minorSpans); minorAllocValid = true; // flush changes to the children updateChildSizes(); } } } /** * Propagates the current allocations to the child views. */ void updateChildSizes() { int n = getViewCount(); if (majorAxis == X_AXIS) { for (int i = 0; i < n; i++) { View v = getView(i); v.setSize((float) majorSpans[i], (float) minorSpans[i]); } } else { for (int i = 0; i < n; i++) { View v = getView(i); v.setSize((float) minorSpans[i], (float) majorSpans[i]); } } } /** * Returns the size of the view along an axis. This is implemented * to return zero. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the current span of the view along the given axis, >= 0 */ float getSpanOnAxis(int axis) { if (axis == majorAxis) { return majorSpan; } else { return minorSpan; } } /** * Sets the size of the view. This should cause * layout of the view if the view caches any layout * information. This is implemented to call the * layout method with the sizes inside of the insets. * * @param width the width >= 0 * @param height the height >= 0 */ public void setSize(float width, float height) { layout(Math.max(0, (int)(width - getLeftInset() - getRightInset())), Math.max(0, (int)(height - getTopInset() - getBottomInset()))); } /** * Renders the <code>BoxView</code> using the given * rendering surface and area * on that surface. Only the children that intersect * the clip bounds of the given <code>Graphics</code> * will be rendered. * * @param g the rendering surface to use * @param allocation the allocated region to render into * @see View#paint */ public void paint(Graphics g, Shape allocation) { Rectangle alloc = (allocation instanceof Rectangle) ? (Rectangle)allocation : allocation.getBounds(); int n = getViewCount(); int x = alloc.x + getLeftInset(); int y = alloc.y + getTopInset(); Rectangle clip = g.getClipBounds(); for (int i = 0; i < n; i++) { tempRect.x = x + getOffset(X_AXIS, i); tempRect.y = y + getOffset(Y_AXIS, i); tempRect.width = getSpan(X_AXIS, i); tempRect.height = getSpan(Y_AXIS, i); int trx0 = tempRect.x, trx1 = trx0 + tempRect.width; int try0 = tempRect.y, try1 = try0 + tempRect.height; int crx0 = clip.x, crx1 = crx0 + clip.width; int cry0 = clip.y, cry1 = cry0 + clip.height; // We should paint views that intersect with clipping region // even if the intersection has no inside points (is a line). // This is needed for supporting views that have zero width, like // views that contain only combining marks. if ((trx1 >= crx0) && (try1 >= cry0) && (crx1 >= trx0) && (cry1 >= try0)) { paintChild(g, tempRect, i); } } } /** * Fetches the allocation for the given child view. * This enables finding out where various views * are located. This is implemented to return * <code>null</code> if the layout is invalid, * otherwise the superclass behavior is executed. * * @param index the index of the child, >= 0 && < getViewCount() * @param a the allocation to this view * @return the allocation to the child; or <code>null</code> * if <code>a</code> is <code>null</code>; * or <code>null</code> if the layout is invalid */ public Shape getChildAllocation(int index, Shape a) { if (a != null) { Shape ca = super.getChildAllocation(index, a); if ((ca != null) && (! isAllocationValid())) { // The child allocation may not have been set yet. Rectangle r = (ca instanceof Rectangle) ? (Rectangle) ca : ca.getBounds(); if ((r.width == 0) && (r.height == 0)) { return null; } } return ca; } return null; } /** * Provides a mapping from the document model coordinate space * to the coordinate space of the view mapped to it. This makes * sure the allocation is valid before calling the superclass. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position * @exception BadLocationException if the given position does * not represent a valid location in the associated document * @see View#modelToView */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { if (! isAllocationValid()) { Rectangle alloc = a.getBounds(); setSize(alloc.width, alloc.height); } return super.modelToView(pos, a, b); } /** * Provides a mapping from the view coordinate space to the logical * coordinate space of the model. * * @param x x coordinate of the view location to convert >= 0 * @param y y coordinate of the view location to convert >= 0 * @param a the allocated region to render into * @return the location within the model that best represents the * given point in the view >= 0 * @see View#viewToModel */ public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { if (! isAllocationValid()) { Rectangle alloc = a.getBounds();