1801 lines · 63.7 KB · Java
RawDownload
/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing.text.html; import java.awt.*;import java.util.BitSet;import java.util.Vector;import java.util.Arrays;import javax.swing.SizeRequirements;import javax.swing.event.DocumentEvent; import javax.swing.text.*; /** * HTML table view. * * @author  Timothy Prinzing * @see     View *//*public*/ class TableView extends BoxView implements ViewFactory {     /**     * Constructs a TableView for the given element.     *     * @param elem the element that this view is responsible for     */    public TableView(Element elem) {        super(elem, View.Y_AXIS);        rows = new Vector<RowView>();        gridValid = false;        captionIndex = -1;        totalColumnRequirements = new SizeRequirements();    }     /**     * Creates a new table row.     *     * @param elem an element     * @return the row     */    protected RowView createTableRow(Element elem) {        // PENDING(prinz) need to add support for some of the other        // elements, but for now just ignore anything that is not        // a TR.        Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);        if (o == HTML.Tag.TR) {            return new RowView(elem);        }        return null;    }     /**     * The number of columns in the table.     */    public int getColumnCount() {        return columnSpans.length;    }     /**     * Fetches the span (width) of the given column.     * This is used by the nested cells to query the     * sizes of grid locations outside of themselves.     */    public int getColumnSpan(int col) {        if (col < columnSpans.length) {            return columnSpans[col];        }        return 0;    }     /**     * The number of rows in the table.     */    public int getRowCount() {        return rows.size();    }     /**     * Fetch the span of multiple rows.  This includes     * the border area.     */    public int getMultiRowSpan(int row0, int row1) {        RowView rv0 = getRow(row0);        RowView rv1 = getRow(row1);        if ((rv0 != null) && (rv1 != null)) {            int index0 = rv0.viewIndex;            int index1 = rv1.viewIndex;            int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) +                getSpan(Y_AXIS, index1);            return span;        }        return 0;    }     /**     * Fetches the span (height) of the given row.     */    public int getRowSpan(int row) {        RowView rv = getRow(row);        if (rv != null) {            return getSpan(Y_AXIS, rv.viewIndex);        }        return 0;    }     RowView getRow(int row) {        if (row < rows.size()) {            return rows.elementAt(row);        }        return null;    }     protected View getViewAtPoint(int x, int y, Rectangle alloc) {        int n = getViewCount();        View v;        Rectangle allocation = new Rectangle();        for (int i = 0; i < n; i++) {            allocation.setBounds(alloc);            childAllocation(i, allocation);            v = getView(i);            if (v instanceof RowView) {                v = ((RowView)v).findViewAtPoint(x, y, allocation);                if (v != null) {                    alloc.setBounds(allocation);                    return v;                }            }        }        return super.getViewAtPoint(x, y, alloc);    }     /**     * Determines the number of columns occupied by     * the table cell represented by given element.     */    protected int getColumnsOccupied(View v) {        AttributeSet a = v.getElement().getAttributes();         if (a.isDefined(HTML.Attribute.COLSPAN)) {            String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);            if (s != null) {                try {                    return Integer.parseInt(s);                } catch (NumberFormatException nfe) {                    // fall through to one column                }            }        }         return 1;    }     /**     * Determines the number of rows occupied by     * the table cell represented by given element.     */    protected int getRowsOccupied(View v) {        AttributeSet a = v.getElement().getAttributes();         if (a.isDefined(HTML.Attribute.ROWSPAN)) {            String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);            if (s != null) {                try {                    return Integer.parseInt(s);                } catch (NumberFormatException nfe) {                    // fall through to one row                }            }        }         return 1;    }     protected void invalidateGrid() {        gridValid = false;    }     protected StyleSheet getStyleSheet() {        HTMLDocument doc = (HTMLDocument) getDocument();        return doc.getStyleSheet();    }     /**     * Update the insets, which contain the caption if there     * is a caption.     */    void updateInsets() {        short top = (short) painter.getInset(TOP, this);        short bottom = (short) painter.getInset(BOTTOM, this);        if (captionIndex != -1) {            View caption = getView(captionIndex);            short h = (short) caption.getPreferredSpan(Y_AXIS);            AttributeSet a = caption.getAttributes();            Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);            if ((align != null) && (align.equals("bottom"))) {                bottom += h;            } else {                top += h;            }        }        setInsets(top, (short) painter.getInset(LEFT, this),                  bottom, (short) painter.getInset(RIGHT, this));    }     /**     * Update any cached values that come from attributes.     */    protected void setPropertiesFromAttributes() {        StyleSheet sheet = getStyleSheet();        attr = sheet.getViewAttributes(this);        painter = sheet.getBoxPainter(attr);        if (attr != null) {            setInsets((short) painter.getInset(TOP, this),                      (short) painter.getInset(LEFT, this),                          (short) painter.getInset(BOTTOM, this),                      (short) painter.getInset(RIGHT, this));             CSS.LengthValue lv = (CSS.LengthValue)                attr.getAttribute(CSS.Attribute.BORDER_SPACING);            if (lv != null) {                cellSpacing = (int) lv.getValue();            } else {                cellSpacing = 0;            }            lv = (CSS.LengthValue)                    attr.getAttribute(CSS.Attribute.BORDER_TOP_WIDTH);            if (lv != null) {                    borderWidth = (int) lv.getValue();            } else {                    borderWidth = 0;            }                 }    }     /**     * Fill in the grid locations that are placeholders     * for multi-column, multi-row, and missing grid     * locations.     */    void updateGrid() {        if (! gridValid) {            relativeCells = false;            multiRowCells = false;             // determine which views are table rows and clear out            // grid points marked filled.            captionIndex = -1;            rows.removeAllElements();            int n = getViewCount();            for (int i = 0; i < n; i++) {                View v = getView(i);                if (v instanceof RowView) {                    rows.addElement((RowView) v);                    RowView rv = (RowView) v;                    rv.clearFilledColumns();                    rv.rowIndex = rows.size() - 1;                    rv.viewIndex = i;                } else {                    Object o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute);                    if (o instanceof HTML.Tag) {                        HTML.Tag kind = (HTML.Tag) o;                        if (kind == HTML.Tag.CAPTION) {                            captionIndex = i;                        }                    }                }            }             int maxColumns = 0;            int nrows = rows.size();            for (int row = 0; row < nrows; row++) {                RowView rv = getRow(row);                int col = 0;                for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {                    View cv = rv.getView(cell);                    if (! relativeCells) {                        AttributeSet a = cv.getAttributes();                        CSS.LengthValue lv = (CSS.LengthValue)                            a.getAttribute(CSS.Attribute.WIDTH);                        if ((lv != null) && (lv.isPercentage())) {                            relativeCells = true;                        }                    }                    // advance to a free column                    for (; rv.isFilled(col); col++);                    int rowSpan = getRowsOccupied(cv);                    if (rowSpan > 1) {                        multiRowCells = true;                    }                    int colSpan = getColumnsOccupied(cv);                    if ((colSpan > 1) || (rowSpan > 1)) {                        // fill in the overflow entries for this cell                        int rowLimit = row + rowSpan;                        int colLimit = col + colSpan;                        for (int i = row; i < rowLimit; i++) {                            for (int j = col; j < colLimit; j++) {                                if (i != row || j != col) {                                    addFill(i, j);                                }                            }                        }                        if (colSpan > 1) {                            col += colSpan - 1;                        }                    }                }                maxColumns = Math.max(maxColumns, col);            }             // setup the column layout/requirements            columnSpans = new int[maxColumns];            columnOffsets = new int[maxColumns];            columnRequirements = new SizeRequirements[maxColumns];            for (int i = 0; i < maxColumns; i++) {                columnRequirements[i] = new SizeRequirements();                columnRequirements[i].maximum = Integer.MAX_VALUE;            }            gridValid = true;        }    }     /**     * Mark a grid location as filled in for a cells overflow.     */    void addFill(int row, int col) {        RowView rv = getRow(row);        if (rv != null) {            rv.fillColumn(col);        }    }     /**     * Layout the columns to fit within the given target span.     *     * @param targetSpan the given span for total of all the table     *  columns     * @param reqs the requirements desired for each column.  This     *  is the column maximum of the cells minimum, preferred, and     *  maximum requested span     * @param spans the return value of how much to allocated to     *  each column     * @param offsets the return value of the offset from the     *  origin for each column     * @return the offset from the origin and the span for each column     *  in the offsets and spans parameters     */    protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,                                 SizeRequirements[] reqs) {        //clean offsets and spans        Arrays.fill(offsets, 0);        Arrays.fill(spans, 0);        colIterator.setLayoutArrays(offsets, spans, targetSpan);        CSS.calculateTiledLayout(colIterator, targetSpan);    }     /**     * Calculate the requirements for each column.  The calculation     * is done as two passes over the table.  The table cells that     * occupy a single column are scanned first to determine the     * maximum of minimum, preferred, and maximum spans along the     * give axis.  Table cells that span multiple columns are excluded     * from the first pass.  A second pass is made to determine if     * the cells that span multiple columns are satisfied.  If the     * column requirements are not satisified, the needs of the     * multi-column cell is mixed into the existing column requirements.     * The calculation of the multi-column distribution is based upon     * the proportions of the existing column requirements and taking     * into consideration any constraining maximums.     */    void calculateColumnRequirements(int axis) {        // clean columnRequirements        for (SizeRequirements req : columnRequirements) {            req.minimum = 0;            req.preferred = 0;            req.maximum = Integer.MAX_VALUE;        }        Container host = getContainer();        if (host != null) {            if (host instanceof JTextComponent) {                skipComments = !((JTextComponent)host).isEditable();            } else {                skipComments = true;            }        }        // pass 1 - single column cells        boolean hasMultiColumn = false;        int nrows = getRowCount();        for (int i = 0; i < nrows; i++) {            RowView row = getRow(i);            int col = 0;            int ncells = row.getViewCount();            for (int cell = 0; cell < ncells; cell++) {                View cv = row.getView(cell);                if (skipComments && !(cv instanceof CellView)) {                    continue;                }                for (; row.isFilled(col); col++); // advance to a free column                int rowSpan = getRowsOccupied(cv);                int colSpan = getColumnsOccupied(cv);                if (colSpan == 1) {                    checkSingleColumnCell(axis, col, cv);                } else {                    hasMultiColumn = true;                    col += colSpan - 1;                }                col++;            }        }         // pass 2 - multi-column cells        if (hasMultiColumn) {            for (int i = 0; i < nrows; i++) {                RowView row = getRow(i);                int col = 0;                int ncells = row.getViewCount();                for (int cell = 0; cell < ncells; cell++) {                    View cv = row.getView(cell);                    if (skipComments && !(cv instanceof CellView)) {                        continue;                    }                    for (; row.isFilled(col); col++); // advance to a free column                    int colSpan = getColumnsOccupied(cv);                    if (colSpan > 1) {                        checkMultiColumnCell(axis, col, colSpan, cv);                        col += colSpan - 1;                    }                    col++;                }            }        }    }     /**     * check the requirements of a table cell that spans a single column.     */    void checkSingleColumnCell(int axis, int col, View v) {        SizeRequirements req = columnRequirements[col];        req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);        req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);    }     /**     * check the requirements of a table cell that spans multiple     * columns.     */    void checkMultiColumnCell(int axis, int col, int ncols, View v) {        // calculate the totals        long min = 0;        long pref = 0;        long max = 0;        for (int i = 0; i < ncols; i++) {            SizeRequirements req = columnRequirements[col + i];            min += req.minimum;            pref += req.preferred;            max += req.maximum;        }         // check if the minimum size needs adjustment.        int cmin = (int) v.getMinimumSpan(axis);        if (cmin > min) {            /*             * the columns that this cell spans need adjustment to fit             * this table cell.... calculate the adjustments.             */            SizeRequirements[] reqs = new SizeRequirements[ncols];            for (int i = 0; i < ncols; i++) {                reqs[i] = columnRequirements[col + i];            }            int[] spans = new int[ncols];            int[] offsets = new int[ncols];            SizeRequirements.calculateTiledPositions(cmin, null, reqs,                                                     offsets, spans);            // apply the adjustments            for (int i = 0; i < ncols; i++) {                SizeRequirements req = reqs[i];                req.minimum = Math.max(spans[i], req.minimum);                req.preferred = Math.max(req.minimum, req.preferred);

Lines 1–500 of 1801.