diff options
Diffstat (limited to 'libjava/classpath/javax/swing/text/AsyncBoxView.java')
-rw-r--r-- | libjava/classpath/javax/swing/text/AsyncBoxView.java | 1480 |
1 files changed, 0 insertions, 1480 deletions
diff --git a/libjava/classpath/javax/swing/text/AsyncBoxView.java b/libjava/classpath/javax/swing/text/AsyncBoxView.java deleted file mode 100644 index aca77aa..0000000 --- a/libjava/classpath/javax/swing/text/AsyncBoxView.java +++ /dev/null @@ -1,1480 +0,0 @@ -/* AsyncBoxView.java -- A box view that performs layout asynchronously - Copyright (C) 2006 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package javax.swing.text; - -import java.awt.Component; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.Shape; -import java.util.ArrayList; - -import javax.swing.event.DocumentEvent; -import javax.swing.text.Position.Bias; - -/** - * A {@link View} implementation that lays out its child views in a box, either - * vertically or horizontally. The difference to {@link BoxView} is that the - * layout is performed in an asynchronous manner. This helps to keep the - * eventqueue free from non-GUI related tasks. - * - * This view is currently not used in standard text components. In order to - * use it you would have to implement a special {@link EditorKit} with a - * {@link ViewFactory} that returns this view. For example: - * - * <pre> - * static class AsyncEditorKit extends StyledEditorKit implements ViewFactory - * { - * public View create(Element el) - * { - * if (el.getName().equals(AbstractDocument.SectionElementName)) - * return new AsyncBoxView(el, View.Y_AXIS); - * return super.getViewFactory().create(el); - * } - * public ViewFactory getViewFactory() { - * return this; - * } - * } - * </pre> - * - * @author Roman Kennke (kennke@aicas.com) - * - * @since 1.3 - */ -public class AsyncBoxView - extends View -{ - - /** - * Manages the effective position of child views. That keeps the visible - * layout stable while the AsyncBoxView might be changing until the layout - * thread decides to publish the new layout. - */ - public class ChildLocator - { - - /** - * The last valid location. - */ - protected ChildState lastValidOffset; - - /** - * The last allocation. - */ - protected Rectangle lastAlloc; - - /** - * A Rectangle used for child allocation calculation to avoid creation - * of lots of garbage Rectangle objects. - */ - protected Rectangle childAlloc; - - /** - * Creates a new ChildLocator. - */ - public ChildLocator() - { - lastAlloc = new Rectangle(); - childAlloc = new Rectangle(); - } - - /** - * Receives notification that a child has changed. This is called by - * child state objects that have changed it's major span. - * - * This sets the {@link #lastValidOffset} field to <code>cs</code> if - * the new child state's view start offset is smaller than the start offset - * of the current child state's view or when <code>lastValidOffset</code> - * is <code>null</code>. - * - * @param cs the child state object that has changed - */ - public synchronized void childChanged(ChildState cs) - { - if (lastValidOffset == null - || cs.getChildView().getStartOffset() - < lastValidOffset.getChildView().getStartOffset()) - { - lastValidOffset = cs; - } - } - - /** - * Returns the view index of the view that occupies the specified area, or - * <code>-1</code> if there is no such child view. - * - * @param x the x coordinate (relative to <code>a</code>) - * @param y the y coordinate (relative to <code>a</code>) - * @param a the current allocation of this view - * - * @return the view index of the view that occupies the specified area, or - * <code>-1</code> if there is no such child view - */ - public int getViewIndexAtPoint(float x, float y, Shape a) - { - setAllocation(a); - float targetOffset = (getMajorAxis() == X_AXIS) ? x - lastAlloc.x - : y - lastAlloc.y; - int index = getViewIndexAtVisualOffset(targetOffset); - return index; - } - - /** - * Returns the current allocation for a child view. This updates the - * offsets for all children <em>before</em> the requested child view. - * - * @param index the index of the child view - * @param a the current allocation of this view - * - * @return the current allocation for a child view - */ - public synchronized Shape getChildAllocation(int index, Shape a) - { - if (a == null) - return null; - setAllocation(a); - ChildState cs = getChildState(index); - if (cs.getChildView().getStartOffset() - > lastValidOffset.getChildView().getStartOffset()) - { - updateChildOffsetsToIndex(index); - } - Shape ca = getChildAllocation(index); - return ca; - } - - /** - * Paints all child views. - * - * @param g the graphics context to use - */ - public synchronized void paintChildren(Graphics g) - { - Rectangle clip = g.getClipBounds(); - float targetOffset = (getMajorAxis() == X_AXIS) ? clip.x - lastAlloc.x - : clip.y - lastAlloc.y; - int index = getViewIndexAtVisualOffset(targetOffset); - int n = getViewCount(); - float offs = getChildState(index).getMajorOffset(); - for (int i = index; i < n; i++) - { - ChildState cs = getChildState(i); - cs.setMajorOffset(offs); - Shape ca = getChildAllocation(i); - if (ca.intersects(clip)) - { - synchronized (cs) - { - View v = cs.getChildView(); - v.paint(g, ca); - } - } - else - { - // done painting intersection - break; - } - offs += cs.getMajorSpan(); - } - } - - /** - * Returns the current allocation of the child view with the specified - * index. Note that this will <em>not</em> update any location information. - * - * @param index the index of the requested child view - * - * @return the current allocation of the child view with the specified - * index - */ - protected Shape getChildAllocation(int index) - { - ChildState cs = getChildState(index); - if (! cs.isLayoutValid()) - cs.run(); - - if (getMajorAxis() == X_AXIS) - { - childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset(); - childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset(); - childAlloc.width = (int) cs.getMajorSpan(); - childAlloc.height = (int) cs.getMinorSpan(); - } - else - { - childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset(); - childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset(); - childAlloc.height = (int) cs.getMajorSpan(); - childAlloc.width = (int) cs.getMinorSpan(); - } - return childAlloc; - } - - /** - * Sets the current allocation for this view. - * - * @param a the allocation to set - */ - protected void setAllocation(Shape a) - { - if (a instanceof Rectangle) - lastAlloc.setBounds((Rectangle) a); - else - lastAlloc.setBounds(a.getBounds()); - - setSize(lastAlloc.width, lastAlloc.height); - } - - /** - * Returns the index of the view at the specified offset along the major - * layout axis. - * - * @param targetOffset the requested offset - * - * @return the index of the view at the specified offset along the major - * layout axis - */ - protected int getViewIndexAtVisualOffset(float targetOffset) - { - int n = getViewCount(); - if (n > 0) - { - if (lastValidOffset == null) - lastValidOffset = getChildState(0); - if (targetOffset > majorSpan) - return 0; - else if (targetOffset > lastValidOffset.getMajorOffset()) - return updateChildOffsets(targetOffset); - else - { - float offs = 0f; - for (int i = 0; i < n; i++) - { - ChildState cs = getChildState(i); - float nextOffs = offs + cs.getMajorSpan(); - if (targetOffset < nextOffs) - return i; - offs = nextOffs; - } - } - } - return n - 1; - } - - /** - * Updates all the child view offsets up to the specified targetOffset. - * - * @param targetOffset the offset up to which the child view offsets are - * updated - * - * @return the index of the view at the specified offset - */ - private int updateChildOffsets(float targetOffset) - { - int n = getViewCount(); - int targetIndex = n - 1; - int pos = lastValidOffset.getChildView().getStartOffset(); - int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); - float start = lastValidOffset.getMajorOffset(); - float lastOffset = start; - for (int i = startIndex; i < n; i++) - { - ChildState cs = getChildState(i); - cs.setMajorOffset(lastOffset); - lastOffset += cs.getMajorSpan(); - if (targetOffset < lastOffset) - { - targetIndex = i; - lastValidOffset = cs; - break; - } - } - return targetIndex; - } - - /** - * Updates the offsets of the child views up to the specified index. - * - * @param index the index up to which the offsets are updated - */ - private void updateChildOffsetsToIndex(int index) - { - int pos = lastValidOffset.getChildView().getStartOffset(); - int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); - float lastOffset = lastValidOffset.getMajorOffset(); - for (int i = startIndex; i <= index; i++) - { - ChildState cs = getChildState(i); - cs.setMajorOffset(lastOffset); - lastOffset += cs.getMajorSpan(); - } - } - } - - /** - * Represents the layout state of a child view. - */ - public class ChildState - implements Runnable - { - - /** - * The child view for this state record. - */ - private View childView; - - /** - * Indicates if the minor axis requirements of this child view are valid - * or not. - */ - private boolean minorValid; - - /** - * Indicates if the major axis requirements of this child view are valid - * or not. - */ - private boolean majorValid; - - /** - * Indicates if the current child size is valid. This is package private - * to avoid synthetic accessor method. - */ - boolean childSizeValid; - - /** - * The child views minimumSpan. This is package private to avoid accessor - * method. - */ - float minimum; - - /** - * The child views preferredSpan. This is package private to avoid accessor - * method. - */ - float preferred; - - /** - * The current span of the child view along the major axis. - */ - private float majorSpan; - - /** - * The current offset of the child view along the major axis. - */ - private float majorOffset; - - /** - * The current span of the child view along the minor axis. - */ - private float minorSpan; - - /** - * The current offset of the child view along the major axis. - */ - private float minorOffset; - - /** - * The child views maximumSpan. - */ - private float maximum; - - /** - * Creates a new <code>ChildState</code> object for the specified child - * view. - * - * @param view the child view for which to create the state record - */ - public ChildState(View view) - { - childView = view; - } - - /** - * Returns the child view for which this <code>ChildState</code> represents - * the layout state. - * - * @return the child view for this child state object - */ - public View getChildView() - { - return childView; - } - - /** - * Returns <code>true</code> if the current layout information is valid, - * <code>false</code> otherwise. - * - * @return <code>true</code> if the current layout information is valid, - * <code>false</code> otherwise - */ - public boolean isLayoutValid() - { - return minorValid && majorValid && childSizeValid; - } - - /** - * Performs the layout update for the child view managed by this - * <code>ChildState</code>. - */ - public void run() - { - Document doc = getDocument(); - if (doc instanceof AbstractDocument) - { - AbstractDocument abstractDoc = (AbstractDocument) doc; - abstractDoc.readLock(); - } - - try - { - - if (!(minorValid && majorValid && childSizeValid) - && childView.getParent() == AsyncBoxView.this) - { - synchronized(AsyncBoxView.this) - { - changing = this; - } - update(); - synchronized(AsyncBoxView.this) - { - changing = null; - } - // Changing the major axis may cause the minor axis - // requirements to have changed, so we need to do this again. - update(); - } - } - finally - { - if (doc instanceof AbstractDocument) - { - AbstractDocument abstractDoc = (AbstractDocument) doc; - abstractDoc.readUnlock(); - } - } - } - - /** - * Performs the actual update after the run methods has made its checks - * and locked the document. - */ - private void update() - { - int majorAxis = getMajorAxis(); - boolean minorUpdated = false; - synchronized (this) - { - if (! minorValid) - { - int minorAxis = getMinorAxis(); - minimum = childView.getMinimumSpan(minorAxis); - preferred = childView.getPreferredSpan(minorAxis); - maximum = childView.getMaximumSpan(minorAxis); - minorValid = true; - minorUpdated = true; - } - } - if (minorUpdated) - minorRequirementChange(this); - - boolean majorUpdated = false; - float delta = 0.0F; - synchronized (this) - { - if (! majorValid) - { - float oldSpan = majorSpan; - majorSpan = childView.getPreferredSpan(majorAxis); - delta = majorSpan - oldSpan; - majorValid = true; - majorUpdated = true; - } - } - if (majorUpdated) - { - majorRequirementChange(this, delta); - locator.childChanged(this); - } - - synchronized (this) - { - if (! childSizeValid) - { - float w; - float h; - if (majorAxis == X_AXIS) - { - w = majorSpan; - h = getMinorSpan(); - } - else - { - w = getMinorSpan(); - h = majorSpan; - } - childSizeValid = true; - childView.setSize(w, h); - } - } - } - - /** - * Returns the span of the child view along the minor layout axis. - * - * @return the span of the child view along the minor layout axis - */ - public float getMinorSpan() - { - float retVal; - if (maximum < minorSpan) - retVal = maximum; - else - retVal = Math.max(minimum, minorSpan); - return retVal; - } - - /** - * Returns the offset of the child view along the minor layout axis. - * - * @return the offset of the child view along the minor layout axis - */ - public float getMinorOffset() - { - float retVal; - if (maximum < minorSpan) - { - float align = childView.getAlignment(getMinorAxis()); - retVal = ((minorSpan - maximum) * align); - } - else - retVal = 0f; - - return retVal; - } - - /** - * Returns the span of the child view along the major layout axis. - * - * @return the span of the child view along the major layout axis - */ - - public float getMajorSpan() - { - return majorSpan; - } - - /** - * Returns the offset of the child view along the major layout axis. - * - * @return the offset of the child view along the major layout axis - */ - public float getMajorOffset() - { - return majorOffset; - } - - /** - * Sets the offset of the child view along the major layout axis. This - * should only be called by the ChildLocator of that child view. - * - * @param offset the offset to set - */ - public void setMajorOffset(float offset) - { - majorOffset = offset; - } - - /** - * Mark the preferences changed for that child. This forwards to - * {@link AsyncBoxView#preferenceChanged}. - * - * @param width <code>true</code> if the width preference has changed - * @param height <code>true</code> if the height preference has changed - */ - public void preferenceChanged(boolean width, boolean height) - { - if (getMajorAxis() == X_AXIS) - { - if (width) - majorValid = false; - if (height) - minorValid = false; - } - else - { - if (width) - minorValid = false; - if (height) - majorValid = false; - } - childSizeValid = false; - } - } - - /** - * Flushes the requirements changes upwards asynchronously. - */ - private class FlushTask implements Runnable - { - /** - * Starts the flush task. This obtains a readLock on the document - * and then flushes all the updates using - * {@link AsyncBoxView#flushRequirementChanges()} after updating the - * requirements. - */ - public void run() - { - try - { - // Acquire a lock on the document. - Document doc = getDocument(); - if (doc instanceof AbstractDocument) - { - AbstractDocument abstractDoc = (AbstractDocument) doc; - abstractDoc.readLock(); - } - - int n = getViewCount(); - if (minorChanged && (n > 0)) - { - LayoutQueue q = getLayoutQueue(); - ChildState min = getChildState(0); - ChildState pref = getChildState(0); - for (int i = 1; i < n; i++) - { - ChildState cs = getChildState(i); - if (cs.minimum > min.minimum) - min = cs; - if (cs.preferred > pref.preferred) - pref = cs; - } - synchronized (AsyncBoxView.this) - { - minReq = min; - prefReq = pref; - } - } - - flushRequirementChanges(); - } - finally - { - // Release the lock on the document. - Document doc = getDocument(); - if (doc instanceof AbstractDocument) - { - AbstractDocument abstractDoc = (AbstractDocument) doc; - abstractDoc.readUnlock(); - } - } - } - - } - - /** - * The major layout axis. - */ - private int majorAxis; - - /** - * The top inset. - */ - private float topInset; - - /** - * The bottom inset. - */ - private float bottomInset; - - /** - * The left inset. - */ - private float leftInset; - - /** - * Indicates if the major span should be treated as beeing estimated or not. - */ - private boolean estimatedMajorSpan; - - /** - * The right inset. - */ - private float rightInset; - - /** - * The children and their layout statistics. - */ - private ArrayList childStates; - - /** - * The currently changing child state. May be null if there is no child state - * updating at the moment. This is package private to avoid a synthetic - * accessor method inside ChildState. - */ - ChildState changing; - - /** - * Represents the minimum requirements. This is used in - * {@link #getMinimumSpan(int)}. - */ - ChildState minReq; - - /** - * Represents the minimum requirements. This is used in - * {@link #getPreferredSpan(int)}. - */ - ChildState prefReq; - - /** - * Indicates that the major axis requirements have changed. - */ - private boolean majorChanged; - - /** - * Indicates that the minor axis requirements have changed. This is package - * private to avoid synthetic accessor method. - */ - boolean minorChanged; - - /** - * The current span along the major layout axis. This is package private to - * avoid synthetic accessor method. - */ - float majorSpan; - - /** - * The current span along the minor layout axis. This is package private to - * avoid synthetic accessor method. - */ - float minorSpan; - - /** - * This tasked is placed on the layout queue to flush updates up to the - * parent view. - */ - private Runnable flushTask; - - /** - * The child locator for this view. - */ - protected ChildLocator locator; - - /** - * Creates a new <code>AsyncBoxView</code> that represents the specified - * element and layouts its children along the specified axis. - * - * @param elem the element - * @param axis the layout axis - */ - public AsyncBoxView(Element elem, int axis) - { - super(elem); - majorAxis = axis; - childStates = new ArrayList(); - flushTask = new FlushTask(); - locator = new ChildLocator(); - minorSpan = Short.MAX_VALUE; - } - - /** - * Returns the major layout axis. - * - * @return the major layout axis - */ - public int getMajorAxis() - { - return majorAxis; - } - - /** - * Returns the minor layout axis, that is the axis orthogonal to the major - * layout axis. - * - * @return the minor layout axis - */ - public int getMinorAxis() - { - return majorAxis == X_AXIS ? Y_AXIS : X_AXIS; - } - - /** - * Returns the view at the specified <code>index</code>. - * - * @param index the index of the requested child view - * - * @return the view at the specified <code>index</code> - */ - public View getView(int index) - { - View view = null; - synchronized(childStates) - { - if ((index >= 0) && (index < childStates.size())) - { - ChildState cs = (ChildState) childStates.get(index); - view = cs.getChildView(); - } - } - return view; - } - - /** - * Returns the number of child views. - * - * @return the number of child views - */ - public int getViewCount() - { - synchronized(childStates) - { - return childStates.size(); - } - } - - /** - * Returns the view index of the child view that represents the specified - * model position. - * - * @param pos the model position for which we search the view index - * @param bias the bias - * - * @return the view index of the child view that represents the specified - * model position - */ - public int getViewIndex(int pos, Position.Bias bias) - { - int retVal = -1; - - if (bias == Position.Bias.Backward) - pos = Math.max(0, pos - 1); - - // TODO: A possible optimization would be to implement a binary search - // here. - int numChildren = childStates.size(); - if (numChildren > 0) - { - for (int i = 0; i < numChildren; ++i) - { - View child = ((ChildState) childStates.get(i)).getChildView(); - if (child.getStartOffset() <= pos && child.getEndOffset() > pos) - { - retVal = i; - break; - } - } - } - return retVal; - } - - /** - * Returns the top inset. - * - * @return the top inset - */ - public float getTopInset() - { - return topInset; - } - - /** - * Sets the top inset. - * - * @param top the top inset - */ - public void setTopInset(float top) - { - topInset = top; - } - - /** - * Returns the bottom inset. - * - * @return the bottom inset - */ - public float getBottomInset() - { - return bottomInset; - } - - /** - * Sets the bottom inset. - * - * @param bottom the bottom inset - */ - public void setBottomInset(float bottom) - { - bottomInset = bottom; - } - - /** - * Returns the left inset. - * - * @return the left inset - */ - public float getLeftInset() - { - return leftInset; - } - - /** - * Sets the left inset. - * - * @param left the left inset - */ - public void setLeftInset(float left) - { - leftInset = left; - } - - /** - * Returns the right inset. - * - * @return the right inset - */ - public float getRightInset() - { - return rightInset; - } - - /** - * Sets the right inset. - * - * @param right the right inset - */ - public void setRightInset(float right) - { - rightInset = right; - } - - /** - * Loads the child views of this view. This is triggered by - * {@link #setParent(View)}. - * - * @param f the view factory to build child views with - */ - protected void loadChildren(ViewFactory f) - { - Element e = getElement(); - int n = e.getElementCount(); - if (n > 0) - { - View[] added = new View[n]; - for (int i = 0; i < n; i++) - { - added[i] = f.create(e.getElement(i)); - } - replace(0, 0, added); - } - } - - /** - * Returns the span along an axis that is taken up by the insets. - * - * @param axis the axis - * - * @return the span along an axis that is taken up by the insets - * - * @since 1.4 - */ - protected float getInsetSpan(int axis) - { - float span; - if (axis == X_AXIS) - span = leftInset + rightInset; - else - span = topInset + bottomInset; - return span; - } - - /** - * Sets the <code>estimatedMajorSpan</code> property that determines if - * the major span should be treated as beeing estimated. - * - * @param estimated if the major span should be treated as estimated or not - * - * @since 1.4 - */ - protected void setEstimatedMajorSpan(boolean estimated) - { - estimatedMajorSpan = estimated; - } - - /** - * Determines whether the major span should be treated as estimated or as - * beeing accurate. - * - * @return <code>true</code> if the major span should be treated as - * estimated, <code>false</code> if the major span should be treated - * as accurate - * - * @since 1.4 - */ - protected boolean getEstimatedMajorSpan() - { - return estimatedMajorSpan; - } - - /** - * Receives notification from the child states that the requirements along - * the minor axis have changed. - * - * @param cs the child state from which this notification is messaged - */ - protected synchronized void minorRequirementChange(ChildState cs) - { - minorChanged = true; - } - - /** - * Receives notification from the child states that the requirements along - * the major axis have changed. - * - * @param cs the child state from which this notification is messaged - */ - protected void majorRequirementChange(ChildState cs, float delta) - { - if (! estimatedMajorSpan) - majorSpan += delta; - majorChanged = true; - } - - /** - * Sets the parent for this view. This calls loadChildren if - * <code>parent</code> is not <code>null</code> and there have not been any - * child views initializes. - * - * @param parent the new parent view; <code>null</code> if this view is - * removed from the view hierarchy - * - * @see View#setParent(View) - */ - public void setParent(View parent) - { - super.setParent(parent); - if ((parent != null) && (getViewCount() == 0)) - { - ViewFactory f = getViewFactory(); - loadChildren(f); - } - } - - /** - * Sets the size of this view. This is ususally called before {@link #paint} - * is called to make sure the view has a valid layout. - * - * This implementation queues layout requests for every child view if the - * minor axis span has changed. (The major axis span is requested to never - * change for this view). - * - * @param width the width of the view - * @param height the height of the view - */ - public void setSize(float width, float height) - { - float targetSpan; - if (majorAxis == X_AXIS) - targetSpan = height - getTopInset() - getBottomInset(); - else - targetSpan = width - getLeftInset() - getRightInset(); - - if (targetSpan != minorSpan) - { - minorSpan = targetSpan; - - int n = getViewCount(); - LayoutQueue q = getLayoutQueue(); - for (int i = 0; i < n; i++) - { - ChildState cs = getChildState(i); - cs.childSizeValid = false; - q.addTask(cs); - } - q.addTask(flushTask); - } - } - - /** - * Replaces child views with new child views. - * - * This creates ChildState objects for all the new views and adds layout - * requests for them to the layout queue. - * - * @param offset the offset at which to remove/insert - * @param length the number of child views to remove - * @param views the new child views to insert - */ - public void replace(int offset, int length, View[] views) - { - synchronized(childStates) - { - LayoutQueue q = getLayoutQueue(); - for (int i = 0; i < length; i++) - childStates.remove(offset); - - for (int i = views.length - 1; i >= 0; i--) - childStates.add(offset, createChildState(views[i])); - - // We need to go through the new child states _after_ they have been - // added to the childStates list, otherwise the layout tasks may find - // an incomplete child list. That means we have to loop through - // them again, but what else can we do? - if (views.length != 0) - { - for (int i = 0; i < views.length; i++) - { - ChildState cs = (ChildState) childStates.get(i + offset); - cs.getChildView().setParent(this); - q.addTask(cs); - } - q.addTask(flushTask); - } - } - } - - /** - * Paints the view. This requests the {@link ChildLocator} to paint the views - * after setting the allocation on it. - * - * @param g the graphics context to use - * @param s the allocation for this view - */ - public void paint(Graphics g, Shape s) - { - synchronized (locator) - { - locator.setAllocation(s); - locator.paintChildren(g); - } - } - - /** - * Returns the preferred span of this view along the specified layout axis. - * - * @return the preferred span of this view along the specified layout axis - */ - public float getPreferredSpan(int axis) - { - float retVal; - if (majorAxis == axis) - retVal = majorSpan; - - else if (prefReq != null) - { - View child = prefReq.getChildView(); - retVal = child.getPreferredSpan(axis); - } - - // If we have no layout information yet, then return insets + 30 as - // an estimation. - else - { - if (axis == X_AXIS) - retVal = getLeftInset() + getRightInset() + 30; - else - retVal = getTopInset() + getBottomInset() + 30; - } - return retVal; - } - - /** - * Maps a model location to view coordinates. - * - * @param pos the model location - * @param a the current allocation of this view - * @param b the bias - * - * @return the view allocation for the specified model location - */ - public Shape modelToView(int pos, Shape a, Bias b) - throws BadLocationException - { - int index = getViewIndexAtPosition(pos, b); - Shape ca = locator.getChildAllocation(index, a); - - ChildState cs = getChildState(index); - synchronized (cs) - { - View cv = cs.getChildView(); - Shape v = cv.modelToView(pos, ca, b); - return v; - } - } - - /** - * Maps view coordinates to a model location. - * - * @param x the x coordinate (relative to <code>a</code>) - * @param y the y coordinate (relative to <code>a</code>) - * @param b holds the bias of the model location on method exit - * - * @return the model location for the specified view location - */ - public int viewToModel(float x, float y, Shape a, Bias[] b) - { - int pos; - int index; - Shape ca; - - synchronized (locator) - { - index = locator.getViewIndexAtPoint(x, y, a); - ca = locator.getChildAllocation(index, a); - } - - ChildState cs = getChildState(index); - synchronized (cs) - { - View v = cs.getChildView(); - pos = v.viewToModel(x, y, ca, b); - } - return pos; - } - - /** - * Returns the child allocation for the child view with the specified - * <code>index</code>. - * - * @param index the index of the child view - * @param a the current allocation of this view - * - * @return the allocation of the child view - */ - public Shape getChildAllocation(int index, Shape a) - { - Shape ca = locator.getChildAllocation(index, a); - return ca; - } - - /** - * Returns the maximum span of this view along the specified axis. - * This is implemented to return the <code>preferredSpan</code> for the - * major axis (that means the box can't be resized along the major axis) and - * {@link Short#MAX_VALUE} for the minor axis. - * - * @param axis the axis - * - * @return the maximum span of this view along the specified axis - */ - public float getMaximumSpan(int axis) - { - float max; - if (axis == majorAxis) - max = getPreferredSpan(axis); - else - max = Short.MAX_VALUE; - return max; - } - - /** - * Returns the minimum span along the specified axis. - */ - public float getMinimumSpan(int axis) - { - float min; - if (axis == majorAxis) - min = getPreferredSpan(axis); - else - { - if (minReq != null) - { - View child = minReq.getChildView(); - min = child.getMinimumSpan(axis); - } - else - { - // No layout information yet. Return insets + 5 as some kind of - // estimation. - if (axis == X_AXIS) - min = getLeftInset() + getRightInset() + 5; - else - min = getTopInset() + getBottomInset() + 5; - } - } - return min; - } - - /** - * Receives notification that one of the child views has changed its - * layout preferences along one or both axis. - * - * This queues a layout request for that child view if necessary. - * - * @param view the view that has changed its preferences - * @param width <code>true</code> if the width preference has changed - * @param height <code>true</code> if the height preference has changed - */ - public synchronized void preferenceChanged(View view, boolean width, - boolean height) - { - if (view == null) - getParent().preferenceChanged(this, width, height); - else - { - if (changing != null) - { - View cv = changing.getChildView(); - if (cv == view) - { - changing.preferenceChanged(width, height); - return; - } - } - int index = getViewIndexAtPosition(view.getStartOffset(), - Position.Bias.Forward); - ChildState cs = getChildState(index); - cs.preferenceChanged(width, height); - LayoutQueue q = getLayoutQueue(); - q.addTask(cs); - q.addTask(flushTask); - } - } - - /** - * Updates the layout for this view. This is implemented to trigger - * {@link ChildLocator#childChanged} for the changed view, if there is - * any. - * - * @param ec the element change, may be <code>null</code> if there were - * no changes to the element of this view - * @param e the document event - * @param a the current allocation of this view - */ - protected void updateLayout(DocumentEvent.ElementChange ec, - DocumentEvent e, Shape a) - { - if (ec != null) - { - int index = Math.max(ec.getIndex() - 1, 0); - ChildState cs = getChildState(index); - locator.childChanged(cs); - } - } - - - /** - * Returns the <code>ChildState</code> object associated with the child view - * at the specified <code>index</code>. - * - * @param index the index of the child view for which to query the state - * - * @return the child state for the specified child view - */ - protected ChildState getChildState(int index) { - synchronized (childStates) - { - return (ChildState) childStates.get(index); - } - } - - /** - * Returns the <code>LayoutQueue</code> used for layouting the box view. - * This simply returns {@link LayoutQueue#getDefaultQueue()}. - * - * @return the <code>LayoutQueue</code> used for layouting the box view - */ - protected LayoutQueue getLayoutQueue() - { - return LayoutQueue.getDefaultQueue(); - } - - /** - * Returns the child view index of the view that represents the specified - * position in the document model. - * - * @param pos the position in the model - * @param b the bias - * - * @return the child view index of the view that represents the specified - * position in the document model - */ - protected synchronized int getViewIndexAtPosition(int pos, Position.Bias b) - { - if (b == Position.Bias.Backward) - pos = Math.max(0, pos - 1); - Element elem = getElement(); - return elem.getElementIndex(pos); - } - - /** - * Creates a <code>ChildState</code> object for the specified view. - * - * @param v the view for which to create a child state object - * - * @return the created child state - */ - protected ChildState createChildState(View v) - { - return new ChildState(v); - } - - /** - * Flushes the requirements changes upwards to the parent view. This is - * called from the layout thread. - */ - protected synchronized void flushRequirementChanges() - { - if (majorChanged || minorChanged) - { - View p = getParent(); - if (p != null) - { - boolean horizontal; - boolean vertical; - if (majorAxis == X_AXIS) - { - horizontal = majorChanged; - vertical = minorChanged; - } - else - { - vertical = majorChanged; - horizontal = minorChanged; - } - - p.preferenceChanged(this, horizontal, vertical); - majorChanged = false; - minorChanged = false; - - Component c = getContainer(); - if (c != null) - c.repaint(); - } - } - } -} |