mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1481 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1481 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* 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();
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| }
 |