| /* 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); | |
| } | |
| } | |
| } |