home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / BoxView.java < prev    next >
Text File  |  1998-02-26  |  21KB  |  698 lines

  1. /*
  2.  * @(#)BoxView.java    1.12 98/01/11
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.io.PrintStream;
  23. import java.util.Vector;
  24. import java.awt.*;
  25. import com.sun.java.swing.event.DocumentEvent;
  26.  
  27. /**
  28.  * A view of a text model that arranges its children into a
  29.  * box.  It might be useful to represent something like a 
  30.  * collection of lines, paragraphs, list items, chunks of text,
  31.  * etc.  The box is somewhat like that found in TeX where
  32.  * there is alignment of the children, flexibility of the
  33.  * children is considered, etc.
  34.  *
  35.  * @author  Timothy Prinzing
  36.  * @version 1.12 01/11/98
  37.  */
  38. public class BoxView extends CompositeView {
  39.  
  40.     /**
  41.      * Constructs a BoxView.
  42.      *
  43.      * @param elem the element this view is responsible for
  44.      * @param axis either X_AXIS or Y_AXIS
  45.      */
  46.     public BoxView(Element elem, int axis) {
  47.     super(elem);
  48.     this.axis = axis;
  49.     }
  50.  
  51.     /**
  52.      * Paints a child.  By default
  53.      * that is all it does, but a subclass can use this to paint 
  54.      * things relative to the child.
  55.      *
  56.      * @param g the graphics context
  57.      * @param alloc the allocated region to paint into
  58.      * @param index the child index
  59.      */
  60.     protected void paintChild(Graphics g, Rectangle alloc, int index) {
  61.     View child = getView(index);
  62.     child.paint(g, alloc);
  63.     }
  64.  
  65.     /**
  66.      * Invalidates the layout and resizes the cache of requests/allocations.
  67.      *
  68.      * @param offset the starting offset into the child views
  69.      * @param length the length
  70.      * @param elems the child views
  71.      */
  72.     public void replace(int offset, int length, View[] elems) {
  73.     super.replace(offset, length, elems);
  74.  
  75.     // invalidate cache 
  76.     xOffsets = null;
  77.     xSpans = null;
  78.     xValid = false;
  79.     xAllocValid = false;
  80.     yOffsets = null;
  81.     ySpans = null;
  82.     yValid = false;
  83.     yAllocValid = false;
  84.     }
  85.  
  86.     // --- View methods ---------------------------------------------
  87.  
  88.     /**
  89.      * This is called by a child to indicated it's 
  90.      * preferred span has changed.  This is implemented to
  91.      * throw away cached layout information so that new
  92.      * calculations will be done the next time the children
  93.      * need an allocation.
  94.      *
  95.      * @param child the child view
  96.      * @param width true if the width preference should change
  97.      * @param height true if the height preference should change
  98.      */
  99.     public void preferenceChanged(View child, boolean width, boolean height) {
  100.     if (width) {
  101.         xValid = false;
  102.         xAllocValid = false;
  103.     }
  104.     if (height) {
  105.         yValid = false;
  106.         yAllocValid = false;
  107.     }
  108.     super.preferenceChanged(child, width, height);
  109.     }
  110.  
  111.     /**
  112.      * Sets the size of the view.  If the size has changed, layout
  113.      * is redone.  The size is the full size of the view including
  114.      * the inset areas.
  115.      *
  116.      * @param width the width
  117.      * @param height the height
  118.      */
  119.     public void setSize(float width, float height) {
  120.     if (((int) width) != this.width) {
  121.         xAllocValid = false;
  122.     }
  123.     if (((int) height) != this.height) { 
  124.         yAllocValid = false;
  125.     }
  126.     if ((! xAllocValid) || (! yAllocValid)) {
  127.         this.width = (int) width;
  128.         this.height = (int) height;
  129.         layout((int) (this.width - getLeftInset() - getRightInset()), 
  130.            (int) (this.height - getTopInset() - getBottomInset()));
  131.     }
  132.     }
  133.  
  134.     /**
  135.      * Renders using the given rendering surface and area on that
  136.      * surface.
  137.      *
  138.      * @param g the rendering surface to use
  139.      * @param allocation the allocated region to render into
  140.      * @see View#paint
  141.      */
  142.     public void paint(Graphics g, Shape allocation) {
  143.     Rectangle alloc = allocation.getBounds();
  144.     setSize(alloc.width, alloc.height);
  145.     int n = getViewCount();
  146.     int x = alloc.x + getLeftInset();
  147.     int y = alloc.y + getTopInset();
  148.     Rectangle clip = g.getClipBounds();
  149.     for (int i = 0; i < n; i++) {
  150.         alloc.x = x + xOffsets[i];
  151.         alloc.y = y + yOffsets[i];
  152.         alloc.width = xSpans[i];
  153.         alloc.height = ySpans[i];
  154.         if (alloc.intersects(clip)) {
  155.         paintChild(g, alloc, i);
  156.         }
  157.     }
  158.     }
  159.  
  160.     /**
  161.      * Provides a mapping from the document model coordinate space
  162.      * to the coordinate space of the view mapped to it.  This makes
  163.      * sure the allocation is valid before letting the superclass
  164.      * do its thing.
  165.      *
  166.      * @param pos the position to convert
  167.      * @param a the allocated region to render into
  168.      * @return the bounding box of the given position
  169.      * @exception BadLocationException  if the given position does not represent a
  170.      *   valid location in the associated document
  171.      * @see View#modelToView
  172.      */
  173.     public Shape modelToView(int pos, Shape a) throws BadLocationException {
  174.     if (! isAllocationValid()) {
  175.         Rectangle alloc = a.getBounds();
  176.         setSize(alloc.width, alloc.height);
  177.     }
  178.     return super.modelToView(pos, a);
  179.     }
  180.  
  181.     /**
  182.      * Provides a mapping from the view coordinate space to the logical
  183.      * coordinate space of the model.
  184.      *
  185.      * @param x   x coordinate of the view location to convert
  186.      * @param y   y coordinate of the view location to convert
  187.      * @param a the allocated region to render into
  188.      * @return the location within the model that best represents the
  189.      *  given point in the view
  190.      * @see View#viewToModel
  191.      */
  192.     public int viewToModel(float x, float y, Shape a) {
  193.     if (! isAllocationValid()) {
  194.         Rectangle alloc = a.getBounds();
  195.         setSize(alloc.width, alloc.height);
  196.     }
  197.     return super.viewToModel(x, y, a);
  198.     }
  199.  
  200.     /**
  201.      * Determines the desired alignment for this view along an
  202.      * axis.  This is implemented to give the total alignment
  203.      * needed to position the children with the alignment points
  204.      * lined up along the axis orthoginal to the axis that is
  205.      * being tiled.  The axis being tiled will request to be
  206.      * centered (ie 0.5f).
  207.      *
  208.      * @param axis may be either X_AXIS or Y_AXIS
  209.      * @returns the desired alignment.  This should be a value
  210.      *   between 0.0 and 1.0 where 0 indicates alignment at the
  211.      *   origin and 1.0 indicates alignment to the full span
  212.      *   away from the origin.  An alignment of 0.5 would be the
  213.      *   center of the view.
  214.      */
  215.     public float getAlignment(int axis) {
  216.     checkRequests();
  217.     switch (axis) {
  218.     case View.X_AXIS:
  219.     case View.Y_AXIS:
  220.         return alignment[axis];
  221.     default:
  222.         throw new IllegalArgumentException("Invalid axis: " + axis);
  223.     }
  224.     }
  225.  
  226.     /**
  227.      * Determines the resizability of the view along the
  228.      * given axis.  A value of 0 or less is not resizable.
  229.      *
  230.      * @param axis may be either X_AXIS or Y_AXIS
  231.      * @return the resize weight
  232.      */
  233.     public int getResizeWeight(int axis) {
  234.     checkRequests();
  235.     switch (axis) {
  236.     case View.X_AXIS:
  237.     case View.Y_AXIS:
  238.         return resizeWeight[axis];
  239.     default:
  240.         throw new IllegalArgumentException("Invalid axis: " + axis);
  241.     }
  242.     }
  243.  
  244.     /**
  245.      * Determines the preferred span for this view along an
  246.      * axis.
  247.      *
  248.      * @param axis may be either X_AXIS or Y_AXIS
  249.      * @returns  the span the view would like to be rendered into.
  250.      *           Typically the view is told to render into the span
  251.      *           that is returned, although there is no guarantee.  
  252.      *           The parent may choose to resize or break the view.
  253.      * @exception IllegalArgumentException for an invalid axis type
  254.      */
  255.     public float getPreferredSpan(int axis) {
  256.     checkRequests();
  257.     switch (axis) {
  258.     case View.X_AXIS:
  259.         return preferredSpan[axis] + getLeftInset() + getRightInset();
  260.     case View.Y_AXIS:
  261.         return preferredSpan[axis] + getTopInset() + getBottomInset();
  262.     default:
  263.         throw new IllegalArgumentException("Invalid axis: " + axis);
  264.     }
  265.     }
  266.  
  267.     /**
  268.      * Gives notification that something was inserted into the document
  269.      * in a location that this view is responsible for.
  270.      *
  271.      * @param e the change information from the associated document
  272.      * @param a the current allocation of the view
  273.      * @param f the factory to use to rebuild if the view has children
  274.      * @see View#insertUpdate
  275.      */
  276.     public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  277.     Element elem = getElement();
  278.     DocumentEvent.ElementChange ec = e.getChange(elem);
  279.     if (ec != null) {
  280.         // the structure of this element changed.
  281.         Element[] removedElems = ec.getChildrenRemoved();
  282.         Element[] addedElems = ec.getChildrenAdded();
  283.         View[] added = new View[addedElems.length];
  284.         for (int i = 0; i < addedElems.length; i++) {
  285.         added[i] = f.create(addedElems[i]);
  286.         }
  287.         replace(ec.getIndex(), removedElems.length, added);
  288.  
  289.         // should damge a little more intelligently.
  290.         if (a != null) {
  291.         preferenceChanged(null, true, true);
  292.         getContainer().repaint();
  293.         }
  294.     }
  295.  
  296.     // find and forward if there is anything there to 
  297.     // forward to.  If children were removed then there was
  298.     // a replacement of the removal range and there is no
  299.     // need to forward.
  300.  
  301.     // PENDING(prinz) fixup DocumentEvent to provide more
  302.     // info so forwarding can be properly done.
  303.     Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  304.         getInsideAllocation(a) : null;
  305.     int pos = e.getOffset();
  306.     View v = getViewAtPosition(pos, alloc);
  307.     if (v != null) {
  308.         v.insertUpdate(e, alloc, f);
  309.         if (v.getStartOffset() == pos) {
  310.         v = getViewAtPosition(pos-1, alloc);
  311.         v.insertUpdate(e, alloc, f);
  312.         }
  313.     }
  314.     }
  315.  
  316.     /**
  317.      * Gives notification that something was removed from the document
  318.      * in a location that this view is responsible for.
  319.      *
  320.      * @param e the change information from the associated document
  321.      * @param a the current allocation of the view
  322.      * @param f the factory to use to rebuild if the view has children
  323.      * @see View#removeUpdate
  324.      */
  325.     public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  326.     Element elem = getElement();
  327.     DocumentEvent.ElementChange ec = e.getChange(elem);
  328.     boolean shouldForward = true;
  329.     if (ec != null) {
  330.         Element[] removedElems = ec.getChildrenRemoved();
  331.         Element[] addedElems = ec.getChildrenAdded();
  332.         View[] added = new View[addedElems.length];
  333.         for (int i = 0; i < addedElems.length; i++) {
  334.         added[i] = f.create(addedElems[i]);
  335.         }
  336.         replace(ec.getIndex(), removedElems.length, added);
  337.         if (added.length != 0) {
  338.         shouldForward = false;
  339.         }
  340.  
  341.         // should damge a little more intelligently.
  342.         if (a != null) {
  343.         preferenceChanged(null, true, true);
  344.         getContainer().repaint();
  345.         }
  346.     }
  347.  
  348.     // find and forward if there is anything there to 
  349.     // forward to.  If children were added then there was
  350.     // a replacement of the removal range and there is no
  351.     // need to forward.
  352.     if (shouldForward) {
  353.         Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  354.         getInsideAllocation(a) : null;
  355.         int pos = e.getOffset();
  356.         View v = getViewAtPosition(pos, alloc);
  357.         if (v != null) {
  358.         v.removeUpdate(e, alloc, f);
  359.         }
  360.     }
  361.     }
  362.  
  363.     /**
  364.      * Gives notification from the document that attributes were changed
  365.      * in a location that this view is responsible for.
  366.      *
  367.      * @param e the change information from the associated document
  368.      * @param a the current allocation of the view
  369.      * @param f the factory to use to rebuild if the view has children
  370.      * @see View#changedUpdate
  371.      */
  372.     public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  373.     Element elem = getElement();
  374.  
  375.         // forward
  376.     Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  377.         getInsideAllocation(a) : null;
  378.     int x = 0;
  379.     int y = 0;
  380.     int width = 0;
  381.     int height = 0;
  382.     if (alloc != null) {
  383.         x = alloc.x;
  384.         y = alloc.y;
  385.         width = alloc.width;
  386.         height = alloc.height;
  387.     }
  388.     int index0 = elem.getElementIndex(e.getOffset());
  389.     int index1 = elem.getElementIndex(e.getOffset() + e.getLength() - 1);
  390.     for (int i = index0; i <= index1; i++) {
  391.         View v = getView(i);
  392.         if (alloc != null) {
  393.         alloc.x = x + xOffsets[i];
  394.         alloc.y = y + yOffsets[i];
  395.         alloc.width = xSpans[i];
  396.         alloc.height = ySpans[i];
  397.         }
  398.         v.changedUpdate(e, alloc, f);
  399.     }
  400.  
  401.     // replace children if necessary.
  402.     DocumentEvent.ElementChange ec = e.getChange(elem);
  403.     if (ec != null) {
  404.         Element[] removedElems = ec.getChildrenRemoved();
  405.         Element[] addedElems = ec.getChildrenAdded();
  406.         View[] added = new View[addedElems.length];
  407.         for (int i = 0; i < addedElems.length; i++) {
  408.         added[i] = f.create(addedElems[i]);
  409.         }
  410.         replace(ec.getIndex(), removedElems.length, added);
  411.     }
  412.     
  413.     if ((a != null) && ! isAllocationValid()) {
  414.         // size changed
  415.         Component c = getContainer();
  416.         c.repaint(x, y, width, height);
  417.     }
  418.     }
  419.  
  420.     // --- local methods ----------------------------------------------------
  421.  
  422.     /**
  423.      * Are the allocations for the children still
  424.      * valid?
  425.      *
  426.      * @return true if allocations still valid
  427.      */
  428.     protected boolean isAllocationValid() {
  429.     return (xAllocValid && yAllocValid);
  430.     }
  431.    
  432.     /**
  433.      * Determines if a point falls before an allocated region.
  434.      *
  435.      * @param x the X coordinate
  436.      * @param y the Y coordinate
  437.      * @param innerAlloc the allocated region.  This is the area
  438.      *   inside of the insets.
  439.      * @return true if the point lies before the region else false
  440.      */
  441.     protected boolean isBefore(int x, int y, Rectangle innerAlloc) {
  442.     if (axis == View.X_AXIS) {
  443.         return (x < innerAlloc.x);
  444.     } else {
  445.         return (y < innerAlloc.y);
  446.     }
  447.     }
  448.  
  449.     /**
  450.      * Determines if a point falls after an allocated region.
  451.      *
  452.      * @param x the X coordinate
  453.      * @param y the Y coordinate
  454.      * @param innerAlloc the allocated region.  This is the area
  455.      *   inside of the insets.
  456.      * @return true if the point lies after the region else false
  457.      */
  458.     protected boolean isAfter(int x, int y, Rectangle innerAlloc) {
  459.     if (axis == View.X_AXIS) {
  460.         return (x > (innerAlloc.width + innerAlloc.x));
  461.     } else {
  462.         return (y > (innerAlloc.height + innerAlloc.y));
  463.     }
  464.     }
  465.  
  466.     /**
  467.      * Fetches the child view at the given point.
  468.      *
  469.      * @param x the X coordinate
  470.      * @param y the Y coordinate
  471.      * @param alloc the parents inner allocation on entry, which should
  472.      *   be changed to the childs allocation on exit.
  473.      * @return the view
  474.      */
  475.     protected View getViewAtPoint(int x, int y, Rectangle alloc) {
  476.     int n = getViewCount();
  477.     if (axis == View.X_AXIS) {
  478.         if (x < (alloc.x + xOffsets[0])) {
  479.         childAllocation(0, alloc);
  480.         return getView(0);
  481.         }
  482.         for (int i = 0; i < n; i++) {
  483.         if (x < (alloc.x + xOffsets[i])) {
  484.             childAllocation(i - 1, alloc);
  485.             return getView(i - 1);
  486.         }
  487.         }
  488.         childAllocation(n - 1, alloc);
  489.         return getView(n - 1);
  490.     } else {
  491.         if (y < (alloc.y + yOffsets[0])) {
  492.         childAllocation(0, alloc);
  493.         return getView(0);
  494.         }
  495.         for (int i = 0; i < n; i++) {
  496.         if (y < (alloc.y + yOffsets[i])) {
  497.             childAllocation(i - 1, alloc);
  498.             return getView(i - 1);
  499.         }
  500.         }
  501.         childAllocation(n - 1, alloc);
  502.         return getView(n - 1);
  503.     }
  504.     }
  505.  
  506.     /**
  507.      * Allocates a region for a child view.  
  508.      *
  509.      * @param index the index of the child view to allocate
  510.      * @param alloc the allocated region
  511.      */
  512.     protected void childAllocation(int index, Rectangle alloc) {
  513.     alloc.x += xOffsets[index];
  514.     alloc.y += yOffsets[index];
  515.     alloc.width = xSpans[index];
  516.     alloc.height = ySpans[index];
  517.     }
  518.  
  519.     /**
  520.      * Performs layout of the children.  The size is the
  521.      * area inside of the insets.
  522.      *
  523.      * @param width the width
  524.      * @param height the height
  525.      */
  526.     protected void layout(int width, int height) {
  527.     checkRequests();
  528.  
  529.     // rebuild the allocation arrays if they've been removed
  530.     // due to a change in child count.
  531.     if (xSpans == null) {
  532.         int n = getViewCount();
  533.         xSpans = new int[n];
  534.         ySpans = new int[n];
  535.         xOffsets = new int[n];
  536.         yOffsets = new int[n];
  537.     }
  538.     if (axis == X_AXIS) {
  539.         if (! xAllocValid) {
  540.         calculateTiledPositions(width, View.X_AXIS);
  541.         }
  542.         if (! yAllocValid) {
  543.         calculateAlignedPositions(height, View.Y_AXIS);
  544.         }
  545.     } else {
  546.         if (! xAllocValid) {
  547.         calculateAlignedPositions(width, View.X_AXIS);
  548.         }
  549.         if (! yAllocValid) {
  550.         calculateTiledPositions(height, View.Y_AXIS);
  551.         }
  552.     }
  553.     xAllocValid = true;
  554.     yAllocValid = true;
  555.  
  556.     // flush changes to the children
  557.     int n = getViewCount();
  558.     for (int i = 0; i < n; i++) {
  559.         View v = getView(i);
  560.         v.setSize((float) xSpans[i], (float) ySpans[i]);
  561.     }
  562.     }
  563.  
  564.     /**
  565.      * Checks the request cache and update if needed.
  566.      */
  567.     void checkRequests() {
  568.     if (axis == X_AXIS) {
  569.         if (! xValid) {
  570.         calculateTiledSizeRequirements(View.X_AXIS);
  571.         }
  572.         if (! yValid) {
  573.         calculateAlignedSizeRequirements(View.Y_AXIS);
  574.         }
  575.     } else {
  576.         if (! xValid) {
  577.         calculateAlignedSizeRequirements(View.X_AXIS);
  578.         }
  579.         if (! yValid) {
  580.         calculateTiledSizeRequirements(View.Y_AXIS);
  581.         }
  582.     }
  583.     yValid = true;
  584.     xValid = true;
  585.     }
  586.  
  587.     /**
  588.      * Determines the total space necessary to
  589.      * place a set of components end-to-end.  
  590.      */
  591.     void calculateTiledSizeRequirements(int axis) {
  592.     alignment[axis] = 0.5f;
  593.     preferredSpan[axis] = 0;
  594.     resizeWeight[axis] = 0;
  595.     int n = getViewCount();
  596.     for (int i = 0; i < n; i++) {
  597.         View v = getView(i);
  598.         preferredSpan[axis] += v.getPreferredSpan(axis);
  599.         resizeWeight[axis] += v.getResizeWeight(axis);
  600.     }
  601.     }
  602.  
  603.     /**
  604.      * Determines the total space necessary to
  605.      * align a set of views along the given axis.
  606.      */
  607.     void calculateAlignedSizeRequirements(int axis) {
  608.  
  609.     int totalAbove = 0;
  610.     int totalBelow = 0;
  611.     int n = getViewCount();
  612.     for (int i = 0; i < n; i++) {
  613.         View v = getView(i);
  614.         int span = (int) v.getPreferredSpan(axis);
  615.         int below = (int) (v.getAlignment(axis) * span);
  616.         int above = span - below;
  617.         totalAbove = Math.max(above, totalAbove);
  618.         totalBelow = Math.max(below, totalBelow);
  619.         resizeWeight[axis] += v.getResizeWeight(axis);
  620.     }
  621.     preferredSpan[axis] = (int) (totalAbove + totalBelow);
  622.     alignment[axis] = 0.5f;
  623.     if (preferredSpan[axis] > 0) {
  624.         alignment[axis] = (float) totalBelow / preferredSpan[axis];
  625.     }
  626.     }
  627.  
  628.     void calculateAlignedPositions(int allocated, int axis) {
  629.     int[] offsets = (axis == View.X_AXIS) ? xOffsets : yOffsets;
  630.     int[] spans = (axis == View.X_AXIS) ? xSpans : ySpans;
  631.  
  632.     int totalBelow = (int) (allocated * alignment[axis]);
  633.     int totalAbove = allocated - totalBelow;
  634.     int n = getViewCount();
  635.     for (int i = 0; i < n; i++) {
  636.         View v = getView(i);
  637.         float align = v.getAlignment(axis);
  638.         int span = (int) v.getPreferredSpan(axis);
  639.         int below = (int) (span * align);
  640.         int above = span - below;
  641.         if (v.getResizeWeight(axis) > 0) {
  642.         below = totalBelow;
  643.         above = totalAbove;
  644.         }
  645.  
  646.         offsets[i] = totalBelow - below;
  647.         spans[i] = (int) (below + above);
  648.     }
  649.     }
  650.  
  651.     void calculateTiledPositions(int allocated, int axis) {
  652.     int[] offsets = (axis == View.X_AXIS) ? xOffsets : yOffsets;
  653.     int[] spans = (axis == View.X_AXIS) ? xSpans : ySpans;
  654.     int totalPlay = allocated - preferredSpan[axis];
  655.     int totalWeight = resizeWeight[axis];
  656.     int totalOffset = 0;
  657.     int n = getViewCount();
  658.     for (int i = 0; i < n; i++) {
  659.         View v = getView(i);
  660.         offsets[i] = totalOffset;
  661.         int span = (int) v.getPreferredSpan(axis);
  662.         int weight = v.getResizeWeight(axis);
  663.         if ((weight != 0) && (totalWeight != 0)) {
  664.         // adjust the span
  665.         float factor = weight / totalWeight;
  666.         span += totalPlay * factor;
  667.         }
  668.         spans[i] = span;
  669.         totalOffset += span;
  670.     }
  671.     }
  672.  
  673.     // --- variables ------------------------------------------------
  674.  
  675.     int axis;
  676.     int width;
  677.     int height;
  678.  
  679.     /**
  680.      * Request cache
  681.      */
  682.     boolean xValid;
  683.     boolean yValid;
  684.     int[] preferredSpan = new int[2];
  685.     int[] resizeWeight = new int[2];
  686.     float[] alignment = new float[2];
  687.  
  688.     /**
  689.      * Allocation cache
  690.      */
  691.     boolean xAllocValid;
  692.     int[] xOffsets;
  693.     int[] xSpans;
  694.     boolean yAllocValid;
  695.     int[] yOffsets;
  696.     int[] ySpans;
  697. }
  698.