mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			975 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			975 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Java
		
	
	
	
/* TableView.java -- A table view for HTML tables
 | 
						|
   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.html;
 | 
						|
 | 
						|
import java.awt.Graphics;
 | 
						|
import java.awt.Rectangle;
 | 
						|
import java.awt.Shape;
 | 
						|
 | 
						|
import gnu.javax.swing.text.html.css.Length;
 | 
						|
 | 
						|
import javax.swing.SizeRequirements;
 | 
						|
import javax.swing.event.DocumentEvent;
 | 
						|
import javax.swing.text.AttributeSet;
 | 
						|
import javax.swing.text.Element;
 | 
						|
import javax.swing.text.StyleConstants;
 | 
						|
import javax.swing.text.View;
 | 
						|
import javax.swing.text.ViewFactory;
 | 
						|
 | 
						|
/**
 | 
						|
 * A view implementation that renders HTML tables.
 | 
						|
 *
 | 
						|
 * This is basically a vertical BoxView that contains the rows of the table
 | 
						|
 * and the rows are horizontal BoxViews that contain the actual columns.
 | 
						|
 */
 | 
						|
class TableView
 | 
						|
  extends BlockView
 | 
						|
  implements ViewFactory
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
   * Represents a single table row.
 | 
						|
   */
 | 
						|
  class RowView
 | 
						|
    extends BlockView
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * Has true at column positions where an above row's cell overlaps into
 | 
						|
     * this row.
 | 
						|
     */
 | 
						|
    boolean[] overlap;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Stores the row index of this row.
 | 
						|
     */
 | 
						|
    int rowIndex;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a new RowView.
 | 
						|
     *
 | 
						|
     * @param el the element for the row view
 | 
						|
     */
 | 
						|
    RowView(Element el)
 | 
						|
    {
 | 
						|
      super(el, X_AXIS);
 | 
						|
    }
 | 
						|
 | 
						|
    public void replace(int offset, int len, View[] views)
 | 
						|
    {
 | 
						|
      gridValid = false;
 | 
						|
      super.replace(offset, len, views);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Overridden to make rows not resizable along the Y axis.
 | 
						|
     */
 | 
						|
    public float getMaximumSpan(int axis)
 | 
						|
    {
 | 
						|
      float span;
 | 
						|
      if (axis == Y_AXIS)
 | 
						|
        span = super.getPreferredSpan(axis);
 | 
						|
      else
 | 
						|
        span = Integer.MAX_VALUE;
 | 
						|
      return span;
 | 
						|
    }
 | 
						|
 | 
						|
    public float getMinimumSpan(int axis)
 | 
						|
    {
 | 
						|
      float span;
 | 
						|
      if (axis == X_AXIS)
 | 
						|
        span = totalColumnRequirements.minimum;
 | 
						|
      else
 | 
						|
        span = super.getMinimumSpan(axis);
 | 
						|
      return span;
 | 
						|
    }
 | 
						|
 | 
						|
    public float getPreferredSpan(int axis)
 | 
						|
    {
 | 
						|
      float span;
 | 
						|
      if (axis == X_AXIS)
 | 
						|
        span = totalColumnRequirements.preferred;
 | 
						|
      else
 | 
						|
        span = super.getPreferredSpan(axis);
 | 
						|
      return span;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Calculates the overall size requirements for the row along the
 | 
						|
     * major axis. This will be the sum of the column requirements.
 | 
						|
     */
 | 
						|
    protected SizeRequirements calculateMajorAxisRequirements(int axis,
 | 
						|
                                                            SizeRequirements r)
 | 
						|
    {
 | 
						|
      if (r == null)
 | 
						|
        r = new SizeRequirements();
 | 
						|
      int adjust = (columnRequirements.length + 1) * cellSpacing;
 | 
						|
      r.minimum = totalColumnRequirements.minimum + adjust;
 | 
						|
      r.preferred = totalColumnRequirements.preferred + adjust;
 | 
						|
      r.maximum = totalColumnRequirements.maximum + adjust;
 | 
						|
      r.alignment = 0.0F;
 | 
						|
      return r;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Lays out the columns in this row.
 | 
						|
     */
 | 
						|
    protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
 | 
						|
                                   int spans[])
 | 
						|
    {
 | 
						|
      super.layoutMinorAxis(targetSpan, axis, offsets, spans);
 | 
						|
 | 
						|
      // Adjust columns that have rowSpan > 1.
 | 
						|
      int numCols = getViewCount();
 | 
						|
      for (int i = 0; i < numCols; i++)
 | 
						|
        {
 | 
						|
          View v = getView(i);
 | 
						|
          if (v instanceof CellView)
 | 
						|
            {
 | 
						|
              CellView cell = (CellView) v;
 | 
						|
              if (cell.rowSpan > 1)
 | 
						|
                {
 | 
						|
                  for (int r = 1; r < cell.rowSpan; r++)
 | 
						|
                    {
 | 
						|
                      spans[i] += TableView.this.getSpan(axis, rowIndex + r);
 | 
						|
                      spans[i] += cellSpacing;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Lays out the columns in this row.
 | 
						|
     */
 | 
						|
    protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
 | 
						|
                                   int spans[])
 | 
						|
    {
 | 
						|
      updateGrid();
 | 
						|
      int realColumn = 0;
 | 
						|
      int colCount = getViewCount();
 | 
						|
      for (int i = 0; i < numColumns;)
 | 
						|
        {
 | 
						|
          if (! overlap[i] && realColumn < colCount)
 | 
						|
            {
 | 
						|
              View v = getView(realColumn);
 | 
						|
              if (v instanceof CellView)
 | 
						|
                {
 | 
						|
                  CellView cv = (CellView) v;
 | 
						|
                  offsets[realColumn] = columnOffsets[i];
 | 
						|
                  spans[realColumn] = 0;
 | 
						|
                  for (int j = 0; j < cv.colSpan; j++, i++)
 | 
						|
                    {
 | 
						|
                      spans[realColumn] += columnSpans[i];
 | 
						|
                      if (j < cv.colSpan - 1)
 | 
						|
                        spans[realColumn] += cellSpacing;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
              realColumn++;
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              i++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A view that renders HTML table cells (TD and TH tags).
 | 
						|
   */
 | 
						|
  class CellView
 | 
						|
    extends BlockView
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * The number of columns that this view spans.
 | 
						|
     */
 | 
						|
    int colSpan;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The number of rows that this cell spans.
 | 
						|
     */
 | 
						|
    int rowSpan;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a new CellView for the specified element.
 | 
						|
     *
 | 
						|
     * @param el the element for which to create the colspan
 | 
						|
     */
 | 
						|
    CellView(Element el)
 | 
						|
    {
 | 
						|
      super(el, Y_AXIS);
 | 
						|
    }
 | 
						|
 | 
						|
    protected SizeRequirements calculateMajorAxisRequirements(int axis,
 | 
						|
                                                            SizeRequirements r)
 | 
						|
    {
 | 
						|
      r = super.calculateMajorAxisRequirements(axis, r);
 | 
						|
      r.maximum = Integer.MAX_VALUE;
 | 
						|
      return r;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Overridden to fetch the columnSpan attibute.
 | 
						|
     */
 | 
						|
    protected void setPropertiesFromAttributes()
 | 
						|
    {
 | 
						|
      super.setPropertiesFromAttributes();
 | 
						|
      colSpan = 1;
 | 
						|
      AttributeSet atts = getAttributes();
 | 
						|
      Object o = atts.getAttribute(HTML.Attribute.COLSPAN);
 | 
						|
      if (o != null)
 | 
						|
        {
 | 
						|
          try
 | 
						|
            {
 | 
						|
              colSpan = Integer.parseInt(o.toString());
 | 
						|
            }
 | 
						|
          catch (NumberFormatException ex)
 | 
						|
            {
 | 
						|
              // Couldn't parse the colspan, assume 1.
 | 
						|
              colSpan = 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      rowSpan = 1;
 | 
						|
      o = atts.getAttribute(HTML.Attribute.ROWSPAN);
 | 
						|
      if (o != null)
 | 
						|
        {
 | 
						|
          try
 | 
						|
            {
 | 
						|
              rowSpan = Integer.parseInt(o.toString());
 | 
						|
            }
 | 
						|
          catch (NumberFormatException ex)
 | 
						|
            {
 | 
						|
              // Couldn't parse the colspan, assume 1.
 | 
						|
              rowSpan = 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * The attributes of this view.
 | 
						|
   */
 | 
						|
  private AttributeSet attributes;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The column requirements.
 | 
						|
   *
 | 
						|
   * Package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  SizeRequirements[] columnRequirements;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The overall requirements across all columns.
 | 
						|
   *
 | 
						|
   * Package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  SizeRequirements totalColumnRequirements;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The column layout, offsets.
 | 
						|
   *
 | 
						|
   * Package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  int[] columnOffsets;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The column layout, spans.
 | 
						|
   *
 | 
						|
   * Package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  int[] columnSpans;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The widths of the columns that have been explicitly specified.
 | 
						|
   */
 | 
						|
  Length[] columnWidths;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The total number of columns.
 | 
						|
   */
 | 
						|
  int numColumns;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The table width.
 | 
						|
   */
 | 
						|
  private Length width;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates if the grid setup is ok.
 | 
						|
   */
 | 
						|
  boolean gridValid = false;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Additional space that is added _between_ table cells.
 | 
						|
   *
 | 
						|
   * This is package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  int cellSpacing;
 | 
						|
 | 
						|
  /**
 | 
						|
   * A cached Rectangle object for reuse in paint().
 | 
						|
   */
 | 
						|
  private Rectangle tmpRect;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a new HTML table view for the specified element.
 | 
						|
   *
 | 
						|
   * @param el the element for the table view
 | 
						|
   */
 | 
						|
  public TableView(Element el)
 | 
						|
  {
 | 
						|
    super(el, Y_AXIS);
 | 
						|
    totalColumnRequirements = new SizeRequirements();
 | 
						|
    tmpRect = new Rectangle();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Implementation of the ViewFactory interface for creating the
 | 
						|
   * child views correctly.
 | 
						|
   */
 | 
						|
  public View create(Element elem)
 | 
						|
  {
 | 
						|
    View view = null;
 | 
						|
    AttributeSet atts = elem.getAttributes();
 | 
						|
    Object name = atts.getAttribute(StyleConstants.NameAttribute);
 | 
						|
    AttributeSet pAtts = elem.getParentElement().getAttributes();
 | 
						|
    Object pName = pAtts.getAttribute(StyleConstants.NameAttribute);
 | 
						|
 | 
						|
    if (name == HTML.Tag.TR && pName == HTML.Tag.TABLE)
 | 
						|
      view = new RowView(elem);
 | 
						|
    else if ((name == HTML.Tag.TD || name == HTML.Tag.TH)
 | 
						|
             && pName == HTML.Tag.TR)
 | 
						|
      view = new CellView(elem);
 | 
						|
    else if (name == HTML.Tag.CAPTION)
 | 
						|
      view = new ParagraphView(elem);
 | 
						|
    else
 | 
						|
      {
 | 
						|
        // If we haven't mapped the element, then fall back to the standard
 | 
						|
        // view factory.
 | 
						|
        View parent = getParent();
 | 
						|
        if (parent != null)
 | 
						|
          {
 | 
						|
            ViewFactory vf = parent.getViewFactory();
 | 
						|
            if (vf != null)
 | 
						|
              view = vf.create(elem);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return view;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns this object as view factory so that we get our TR, TD, TH
 | 
						|
   * and CAPTION subelements created correctly.
 | 
						|
   */
 | 
						|
  public ViewFactory getViewFactory()
 | 
						|
  {
 | 
						|
    return this;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the attributes of this view. This is overridden to provide
 | 
						|
   * the attributes merged with the CSS stuff.
 | 
						|
   */
 | 
						|
  public AttributeSet getAttributes()
 | 
						|
  {
 | 
						|
    if (attributes == null)
 | 
						|
      attributes = getStyleSheet().getViewAttributes(this);
 | 
						|
    return attributes;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the stylesheet associated with this view.
 | 
						|
   *
 | 
						|
   * @return the stylesheet associated with this view
 | 
						|
   */
 | 
						|
  protected StyleSheet getStyleSheet()
 | 
						|
  {
 | 
						|
    HTMLDocument doc = (HTMLDocument) getDocument();
 | 
						|
    return doc.getStyleSheet();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to calculate the size requirements according to the
 | 
						|
   * columns distribution.
 | 
						|
   */
 | 
						|
  protected SizeRequirements calculateMinorAxisRequirements(int axis,
 | 
						|
                                                            SizeRequirements r)
 | 
						|
  {
 | 
						|
    updateGrid();
 | 
						|
    calculateColumnRequirements();
 | 
						|
 | 
						|
    // Calculate the horizontal requirements according to the superclass.
 | 
						|
    // This will return the maximum of the row's widths.
 | 
						|
    r = super.calculateMinorAxisRequirements(axis, r);
 | 
						|
 | 
						|
    // Try to set the CSS width if it fits.
 | 
						|
    if (width != null)
 | 
						|
      {
 | 
						|
        int w = (int) width.getValue();
 | 
						|
        if (r.minimum < w)
 | 
						|
          r.minimum = w;
 | 
						|
      }
 | 
						|
 | 
						|
    // Adjust requirements when we have cell spacing.
 | 
						|
    int adjust = (columnRequirements.length + 1) * cellSpacing;
 | 
						|
    r.minimum += adjust;
 | 
						|
    r.preferred += adjust;
 | 
						|
 | 
						|
    // Apply the alignment.
 | 
						|
    AttributeSet atts = getAttributes();
 | 
						|
    Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN);
 | 
						|
    r.alignment = 0.0F;
 | 
						|
    if (o != null)
 | 
						|
      {
 | 
						|
        String al = o.toString();
 | 
						|
        if (al.equals("left"))
 | 
						|
          r.alignment = 0.0F;
 | 
						|
        else if (al.equals("center"))
 | 
						|
          r.alignment = 0.5F;
 | 
						|
        else if (al.equals("right"))
 | 
						|
          r.alignment = 1.0F;
 | 
						|
      }
 | 
						|
 | 
						|
    // Make it not resize in the horizontal direction.
 | 
						|
    r.maximum = r.preferred;
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to perform the table layout before calling the super
 | 
						|
   * implementation.
 | 
						|
   */
 | 
						|
  protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
 | 
						|
                                 int[] spans)
 | 
						|
  {
 | 
						|
    updateGrid();
 | 
						|
 | 
						|
    // Mark all rows as invalid along their minor axis to force correct
 | 
						|
    // layout of multi-row cells.
 | 
						|
    int n = getViewCount();
 | 
						|
    for (int i = 0; i < n; i++)
 | 
						|
      {
 | 
						|
        View row = getView(i);
 | 
						|
        if (row instanceof RowView)
 | 
						|
          ((RowView) row).layoutChanged(axis);
 | 
						|
      }
 | 
						|
 | 
						|
    layoutColumns(targetSpan);
 | 
						|
    super.layoutMinorAxis(targetSpan, axis, offsets, spans);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Calculates the size requirements for the columns.
 | 
						|
   */
 | 
						|
  private void calculateColumnRequirements()
 | 
						|
  {
 | 
						|
    int numRows = getViewCount();
 | 
						|
    totalColumnRequirements.minimum = 0;
 | 
						|
    totalColumnRequirements.preferred = 0;
 | 
						|
    totalColumnRequirements.maximum = 0;
 | 
						|
 | 
						|
    // In this first pass we find out a suitable total width to fit in
 | 
						|
    // all columns of all rows.
 | 
						|
    for (int r = 0; r < numRows; r++)
 | 
						|
      {
 | 
						|
        View rowView = getView(r);
 | 
						|
        int numCols;
 | 
						|
        if (rowView instanceof RowView)
 | 
						|
          numCols = ((RowView) rowView).getViewCount();
 | 
						|
        else
 | 
						|
          numCols = 0;
 | 
						|
 | 
						|
        // We collect the normal (non-relative) column requirements in the
 | 
						|
        // total variable and the relative requirements in the relTotal
 | 
						|
        // variable. In the end we create the maximum of both to get the
 | 
						|
        // real requirements.
 | 
						|
        SizeRequirements total = new SizeRequirements();
 | 
						|
        SizeRequirements relTotal = new SizeRequirements();
 | 
						|
        float totalPercent = 0.F;
 | 
						|
        int realCol = 0;
 | 
						|
        for (int c = 0; c < numCols; c++)
 | 
						|
          {
 | 
						|
            View v = rowView.getView(c);
 | 
						|
            if (v instanceof CellView)
 | 
						|
              {
 | 
						|
                CellView cellView = (CellView) v;
 | 
						|
                int colSpan = cellView.colSpan;
 | 
						|
                if (colSpan > 1)
 | 
						|
                  {
 | 
						|
                    int cellMin = (int) cellView.getMinimumSpan(X_AXIS);
 | 
						|
                    int cellPref = (int) cellView.getPreferredSpan(X_AXIS);
 | 
						|
                    int cellMax = (int) cellView.getMaximumSpan(X_AXIS);
 | 
						|
                    int currentMin = 0;
 | 
						|
                    int currentPref = 0;
 | 
						|
                    long currentMax = 0;
 | 
						|
                    for (int i = 0; i < colSpan; i++)
 | 
						|
                      {
 | 
						|
                        SizeRequirements req = columnRequirements[realCol];
 | 
						|
                        currentMin += req.minimum;
 | 
						|
                        currentPref += req.preferred;
 | 
						|
                        currentMax += req.maximum;
 | 
						|
                      }
 | 
						|
                    int deltaMin = cellMin - currentMin;
 | 
						|
                    int deltaPref = cellPref - currentPref;
 | 
						|
                    int deltaMax = (int) (cellMax - currentMax);
 | 
						|
                    // Distribute delta.
 | 
						|
                    for (int i = 0; i < colSpan; i++)
 | 
						|
                      {
 | 
						|
                        SizeRequirements req = columnRequirements[realCol];
 | 
						|
                        if (deltaMin > 0)
 | 
						|
                          req.minimum += deltaMin / colSpan;
 | 
						|
                        if (deltaPref > 0)
 | 
						|
                          req.preferred += deltaPref / colSpan;
 | 
						|
                        if (deltaMax > 0)
 | 
						|
                          req.maximum += deltaMax / colSpan;
 | 
						|
                        if (columnWidths[realCol] == null
 | 
						|
                            || ! columnWidths[realCol].isPercentage())
 | 
						|
                          {
 | 
						|
                            total.minimum += req.minimum;
 | 
						|
                            total.preferred += req.preferred;
 | 
						|
                            total.maximum += req.maximum;
 | 
						|
                          }
 | 
						|
                        else
 | 
						|
                          {
 | 
						|
                            relTotal.minimum =
 | 
						|
                              Math.max(relTotal.minimum,
 | 
						|
                                     (int) (req.minimum
 | 
						|
                                          * columnWidths[realCol].getValue()));
 | 
						|
                            relTotal.preferred =
 | 
						|
                              Math.max(relTotal.preferred,
 | 
						|
                                     (int) (req.preferred
 | 
						|
                                          * columnWidths[realCol].getValue()));
 | 
						|
                            relTotal.maximum =
 | 
						|
                              Math.max(relTotal.maximum,
 | 
						|
                                     (int) (req.maximum
 | 
						|
                                          * columnWidths[realCol].getValue()));
 | 
						|
                            totalPercent += columnWidths[realCol].getValue();
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                    realCol += colSpan;
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    // Shortcut for colSpan == 1.
 | 
						|
                    SizeRequirements req = columnRequirements[realCol];
 | 
						|
                    req.minimum = Math.max(req.minimum,
 | 
						|
                                        (int) cellView.getMinimumSpan(X_AXIS));
 | 
						|
                    req.preferred = Math.max(req.preferred,
 | 
						|
                                      (int) cellView.getPreferredSpan(X_AXIS));
 | 
						|
                    req.maximum = Math.max(req.maximum,
 | 
						|
                                        (int) cellView.getMaximumSpan(X_AXIS));
 | 
						|
                    if (columnWidths[realCol] == null
 | 
						|
                        || ! columnWidths[realCol].isPercentage())
 | 
						|
                      {
 | 
						|
                        total.minimum += columnRequirements[realCol].minimum;
 | 
						|
                        total.preferred +=
 | 
						|
                          columnRequirements[realCol].preferred;
 | 
						|
                        total.maximum += columnRequirements[realCol].maximum;
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        relTotal.minimum =
 | 
						|
                          Math.max(relTotal.minimum,
 | 
						|
                                 (int) (req.minimum
 | 
						|
                                        / columnWidths[c].getValue()));
 | 
						|
                        relTotal.preferred =
 | 
						|
                          Math.max(relTotal.preferred,
 | 
						|
                                 (int) (req.preferred
 | 
						|
                                        / columnWidths[c].getValue()));
 | 
						|
                        relTotal.maximum =
 | 
						|
                          Math.max(relTotal.maximum,
 | 
						|
                                 (int) (req.maximum
 | 
						|
                                        / columnWidths[c].getValue()));
 | 
						|
                        totalPercent += columnWidths[c].getValue();
 | 
						|
                      }
 | 
						|
                    realCol += 1;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        // Update the total requirements as follows:
 | 
						|
        // 1. Multiply the absolute requirements with 1 - totalPercent. This
 | 
						|
        //    gives the total requirements based on the wishes of the absolute
 | 
						|
        //    cells.
 | 
						|
        // 2. Take the maximum of this value and the total relative
 | 
						|
        //    requirements. Now we should have enough space for whatever cell
 | 
						|
        //    in this column.
 | 
						|
        // 3. Take the maximum of this value and the previous maximum value.
 | 
						|
        total.minimum *= 1.F / (1.F - totalPercent);
 | 
						|
        total.preferred *= 1.F / (1.F - totalPercent);
 | 
						|
        total.maximum *= 1.F / (1.F - totalPercent);
 | 
						|
 | 
						|
        int rowTotalMin = Math.max(total.minimum, relTotal.minimum);
 | 
						|
        int rowTotalPref = Math.max(total.preferred, relTotal.preferred);
 | 
						|
        int rowTotalMax = Math.max(total.maximum, relTotal.maximum);
 | 
						|
        totalColumnRequirements.minimum =
 | 
						|
          Math.max(totalColumnRequirements.minimum, rowTotalMin);
 | 
						|
        totalColumnRequirements.preferred =
 | 
						|
          Math.max(totalColumnRequirements.preferred, rowTotalPref);
 | 
						|
        totalColumnRequirements.maximum =
 | 
						|
          Math.max(totalColumnRequirements.maximum, rowTotalMax);
 | 
						|
      }
 | 
						|
 | 
						|
    // Now we know what we want and can fix up the actual relative
 | 
						|
    // column requirements.
 | 
						|
    int numCols = columnRequirements.length;
 | 
						|
    for (int i = 0; i < numCols; i++)
 | 
						|
      {
 | 
						|
        if (columnWidths[i] != null)
 | 
						|
          {
 | 
						|
            columnRequirements[i].minimum = (int)
 | 
						|
              columnWidths[i].getValue(totalColumnRequirements.minimum);
 | 
						|
            columnRequirements[i].preferred = (int)
 | 
						|
              columnWidths[i].getValue(totalColumnRequirements.preferred);
 | 
						|
            columnRequirements[i].maximum = (int)
 | 
						|
              columnWidths[i].getValue(totalColumnRequirements.maximum);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Lays out the columns.
 | 
						|
   *
 | 
						|
   * @param targetSpan the target span into which the table is laid out
 | 
						|
   */
 | 
						|
  private void layoutColumns(int targetSpan)
 | 
						|
  {
 | 
						|
    // Set the spans to the preferred sizes. Determine the space
 | 
						|
    // that we have to adjust the sizes afterwards.
 | 
						|
    long sumPref = 0;
 | 
						|
    int n = columnRequirements.length;
 | 
						|
    for (int i = 0; i < n; i++)
 | 
						|
      {
 | 
						|
        SizeRequirements col = columnRequirements[i];
 | 
						|
        if (columnWidths[i] != null)
 | 
						|
          columnSpans[i] = (int) columnWidths[i].getValue(targetSpan);
 | 
						|
        else
 | 
						|
          columnSpans[i] = col.preferred;
 | 
						|
        sumPref += columnSpans[i];
 | 
						|
      }
 | 
						|
 | 
						|
    // Try to adjust the spans so that we fill the targetSpan.
 | 
						|
    // For adjustments we have to use the targetSpan minus the cumulated
 | 
						|
    // cell spacings.
 | 
						|
    long diff = targetSpan - (n + 1) * cellSpacing - sumPref;
 | 
						|
    float factor = 0.0F;
 | 
						|
    int[] diffs = null;
 | 
						|
    if (diff != 0)
 | 
						|
      {
 | 
						|
        long total = 0;
 | 
						|
        diffs = new int[n];
 | 
						|
        for (int i = 0; i < n; i++)
 | 
						|
          {
 | 
						|
            // Only adjust the width if we haven't set a column width here.
 | 
						|
            if (columnWidths[i] == null)
 | 
						|
              {
 | 
						|
                SizeRequirements col = columnRequirements[i];
 | 
						|
                int span;
 | 
						|
                if (diff < 0)
 | 
						|
                  {
 | 
						|
                    span = col.minimum;
 | 
						|
                    diffs[i] = columnSpans[i] - span;
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    span = col.maximum;
 | 
						|
                    diffs[i] = span - columnSpans[i];
 | 
						|
                  }
 | 
						|
                total += span;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              total += columnSpans[i];
 | 
						|
          }
 | 
						|
 | 
						|
        float maxAdjust = Math.abs(total - sumPref);
 | 
						|
        factor = diff / maxAdjust;
 | 
						|
        factor = Math.min(factor, 1.0F);
 | 
						|
        factor = Math.max(factor, -1.0F);
 | 
						|
      }
 | 
						|
 | 
						|
    // Actually perform adjustments.
 | 
						|
    int totalOffs = cellSpacing;
 | 
						|
    for (int i = 0; i < n; i++)
 | 
						|
      {
 | 
						|
        columnOffsets[i] = totalOffs;
 | 
						|
        if (diff != 0)
 | 
						|
          {
 | 
						|
            float adjust = factor * diffs[i];
 | 
						|
            columnSpans[i] += Math.round(adjust);
 | 
						|
          }
 | 
						|
        // Avoid overflow here.
 | 
						|
        totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i]
 | 
						|
                                   + (long) cellSpacing, Integer.MAX_VALUE);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Updates the arrays that contain the row and column data in response
 | 
						|
   * to a change to the table structure.
 | 
						|
   *
 | 
						|
   * Package private to avoid accessor methods.
 | 
						|
   */
 | 
						|
  void updateGrid()
 | 
						|
  {
 | 
						|
    if (! gridValid)
 | 
						|
      {
 | 
						|
        AttributeSet atts = getAttributes();
 | 
						|
        StyleSheet ss = getStyleSheet();
 | 
						|
        float emBase = ss.getEMBase(atts);
 | 
						|
        float exBase = ss.getEXBase(atts);
 | 
						|
        int maxColumns = 0;
 | 
						|
        int numRows = getViewCount();
 | 
						|
        for (int r = 0; r < numRows; r++)
 | 
						|
          {
 | 
						|
            View rowView = getView(r);
 | 
						|
            int numCols = 0;
 | 
						|
            if (rowView instanceof RowView)
 | 
						|
              {
 | 
						|
                int numCells = ((RowView) rowView).getViewCount();
 | 
						|
                for (int i = 0; i < numCells; i++)
 | 
						|
                  {
 | 
						|
                    View v = rowView.getView(i);
 | 
						|
                    if (v instanceof CellView)
 | 
						|
                      numCols += ((CellView) v).colSpan;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            maxColumns = Math.max(numCols, maxColumns);
 | 
						|
          }
 | 
						|
        numColumns = maxColumns;
 | 
						|
        columnWidths = new Length[maxColumns];
 | 
						|
        int[] rowSpans = new int[maxColumns];
 | 
						|
        for (int r = 0; r < numRows; r++)
 | 
						|
          {
 | 
						|
            View view = getView(r);
 | 
						|
            if (view instanceof RowView)
 | 
						|
              {
 | 
						|
                RowView rowView = (RowView) view;
 | 
						|
                rowView.rowIndex = r;
 | 
						|
                rowView.overlap = new boolean[maxColumns];
 | 
						|
                int colIndex = 0;
 | 
						|
                int colCount = rowView.getViewCount();
 | 
						|
                for (int c = 0; c < maxColumns;)
 | 
						|
                  {
 | 
						|
                    if (rowSpans[c] > 0)
 | 
						|
                      {
 | 
						|
                        rowSpans[c]--;
 | 
						|
                        rowView.overlap[c] = true;
 | 
						|
                        c++;
 | 
						|
                      }
 | 
						|
                    else if (colIndex < colCount)
 | 
						|
                      {
 | 
						|
                        View v = rowView.getView(colIndex);
 | 
						|
                        colIndex++;
 | 
						|
                        if (v instanceof CellView)
 | 
						|
                          {
 | 
						|
                            CellView cv = (CellView) v;
 | 
						|
                            Object o =
 | 
						|
                              cv.getAttributes().getAttribute(CSS.Attribute.WIDTH);
 | 
						|
                            if (o != null && columnWidths[c] == null
 | 
						|
                                && o instanceof Length)
 | 
						|
                              {
 | 
						|
                                columnWidths[c]= (Length) o;
 | 
						|
                                columnWidths[c].setFontBases(emBase, exBase);
 | 
						|
                              }
 | 
						|
                            int rs = cv.rowSpan - 1;
 | 
						|
                            for (int col = cv.colSpan - 1; col >= 0; col--)
 | 
						|
                              {
 | 
						|
                                rowSpans[c] = rs;
 | 
						|
                                c++;
 | 
						|
                              }
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        c++;
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
        columnRequirements = new SizeRequirements[maxColumns];
 | 
						|
        for (int i = 0; i < maxColumns; i++)
 | 
						|
          columnRequirements[i] = new SizeRequirements();
 | 
						|
        columnOffsets = new int[maxColumns];
 | 
						|
        columnSpans = new int[maxColumns];
 | 
						|
 | 
						|
        gridValid = true;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to restrict the table width to the preferred size.
 | 
						|
   */
 | 
						|
  public float getMaximumSpan(int axis)
 | 
						|
  {
 | 
						|
    float span;
 | 
						|
    if (axis == X_AXIS)
 | 
						|
      span = super.getPreferredSpan(axis);
 | 
						|
    else
 | 
						|
      span = super.getMaximumSpan(axis);
 | 
						|
    return span;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to fetch the CSS attributes when view gets connected.
 | 
						|
   */
 | 
						|
  public void setParent(View parent)
 | 
						|
  {
 | 
						|
    super.setParent(parent);
 | 
						|
    if (parent != null)
 | 
						|
      setPropertiesFromAttributes();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fetches CSS and HTML layout attributes.
 | 
						|
   */
 | 
						|
  protected void setPropertiesFromAttributes()
 | 
						|
  {
 | 
						|
    super.setPropertiesFromAttributes();
 | 
						|
 | 
						|
    // Fetch and parse cell spacing.
 | 
						|
    AttributeSet atts = getAttributes();
 | 
						|
    StyleSheet ss = getStyleSheet();
 | 
						|
    float emBase = ss.getEMBase(atts);
 | 
						|
    float exBase = ss.getEXBase(atts);
 | 
						|
    Object o = atts.getAttribute(CSS.Attribute.BORDER_SPACING);
 | 
						|
    if (o != null && o instanceof Length)
 | 
						|
      {
 | 
						|
        Length l = (Length) o;
 | 
						|
        l.setFontBases(emBase, exBase);
 | 
						|
        cellSpacing = (int) l.getValue();
 | 
						|
      }
 | 
						|
    o = atts.getAttribute(CSS.Attribute.WIDTH);
 | 
						|
    if (o != null && o instanceof Length)
 | 
						|
      {
 | 
						|
        width = (Length) o;
 | 
						|
        width.setFontBases(emBase, exBase);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to adjust for cellSpacing.
 | 
						|
   */
 | 
						|
  protected SizeRequirements calculateMajorAxisRequirements(int axis,
 | 
						|
                                                            SizeRequirements r)
 | 
						|
  {
 | 
						|
    r = super.calculateMajorAxisRequirements(axis, r);
 | 
						|
    int adjust = (getViewCount() + 1) * cellSpacing;
 | 
						|
    r.minimum += adjust;
 | 
						|
    r.preferred += adjust;
 | 
						|
    r.maximum += adjust;
 | 
						|
    return r;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to adjust for cellSpacing.
 | 
						|
   */
 | 
						|
  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
 | 
						|
                                 int spans[])
 | 
						|
  {
 | 
						|
    // Mark all rows as invalid along their minor axis to force correct
 | 
						|
    // layout of multi-row cells.
 | 
						|
    int n = getViewCount();
 | 
						|
    for (int i = 0; i < n; i++)
 | 
						|
      {
 | 
						|
        View row = getView(i);
 | 
						|
        if (row instanceof RowView)
 | 
						|
          ((RowView) row).layoutChanged(axis);
 | 
						|
      }
 | 
						|
 | 
						|
    int adjust = (getViewCount() + 1) * cellSpacing;
 | 
						|
    super.layoutMajorAxis(targetSpan - adjust, axis, offsets, spans);
 | 
						|
    for (int i = 0; i < offsets.length; i++)
 | 
						|
      {
 | 
						|
        offsets[i] += (i + 1) * cellSpacing;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to replace view factory with this one.
 | 
						|
   */
 | 
						|
  public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f)
 | 
						|
  {
 | 
						|
    super.insertUpdate(e, a, this);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to replace view factory with this one.
 | 
						|
   */
 | 
						|
  public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f)
 | 
						|
  {
 | 
						|
    super.removeUpdate(e, a, this);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overridden to replace view factory with this one.
 | 
						|
   */
 | 
						|
  public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)
 | 
						|
  {
 | 
						|
    super.changedUpdate(e, a, this);
 | 
						|
  }
 | 
						|
 | 
						|
  public void replace(int offset, int len, View[] views)
 | 
						|
  {
 | 
						|
    gridValid = false;
 | 
						|
    super.replace(offset, len, views);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * We can't use the super class's paint() method because it might cut
 | 
						|
   * off multi-row children. Instead we trigger painting for all rows
 | 
						|
   * and let the rows sort out what to paint and what not.
 | 
						|
   */
 | 
						|
  public void paint(Graphics g, Shape a)
 | 
						|
  {
 | 
						|
    Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
 | 
						|
    painter.paint(g, rect.x, rect.y, rect.width, rect.height, this);
 | 
						|
    int nRows = getViewCount();
 | 
						|
    Rectangle inside = getInsideAllocation(a);
 | 
						|
    for (int r = 0; r < nRows; r++)
 | 
						|
      {
 | 
						|
        tmpRect.setBounds(inside);
 | 
						|
        childAllocation(r, tmpRect);
 | 
						|
        paintChild(g, tmpRect, r);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
}
 |