Source Code Cross Referenced for TableView.java in  » 6.0-JDK-Core » swing » javax » swing » text » html » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text.html 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing.text.html;
0026
0027        import java.awt.*;
0028        import java.util.BitSet;
0029        import java.util.Vector;
0030        import java.util.Arrays;
0031        import javax.swing.SizeRequirements;
0032        import javax.swing.event.DocumentEvent;
0033
0034        import javax.swing.text.*;
0035
0036        /**
0037         * HTML table view.  
0038         * 
0039         * @author  Timothy Prinzing
0040         * @version 1.47 05/05/07
0041         * @see     View
0042         */
0043        /*public*/class TableView extends BoxView implements  ViewFactory {
0044
0045            /**
0046             * Constructs a TableView for the given element.
0047             *
0048             * @param elem the element that this view is responsible for
0049             */
0050            public TableView(Element elem) {
0051                super (elem, View.Y_AXIS);
0052                rows = new Vector();
0053                gridValid = false;
0054                captionIndex = -1;
0055                totalColumnRequirements = new SizeRequirements();
0056            }
0057
0058            /**
0059             * Creates a new table row.
0060             *
0061             * @param elem an element
0062             * @return the row
0063             */
0064            protected RowView createTableRow(Element elem) {
0065                // PENDING(prinz) need to add support for some of the other
0066                // elements, but for now just ignore anything that is not
0067                // a TR.
0068                Object o = elem.getAttributes().getAttribute(
0069                        StyleConstants.NameAttribute);
0070                if (o == HTML.Tag.TR) {
0071                    return new RowView(elem);
0072                }
0073                return null;
0074            }
0075
0076            /**
0077             * The number of columns in the table.
0078             */
0079            public int getColumnCount() {
0080                return columnSpans.length;
0081            }
0082
0083            /**
0084             * Fetches the span (width) of the given column.  
0085             * This is used by the nested cells to query the 
0086             * sizes of grid locations outside of themselves.
0087             */
0088            public int getColumnSpan(int col) {
0089                if (col < columnSpans.length) {
0090                    return columnSpans[col];
0091                }
0092                return 0;
0093            }
0094
0095            /**
0096             * The number of rows in the table.
0097             */
0098            public int getRowCount() {
0099                return rows.size();
0100            }
0101
0102            /**
0103             * Fetch the span of multiple rows.  This includes
0104             * the border area.
0105             */
0106            public int getMultiRowSpan(int row0, int row1) {
0107                RowView rv0 = getRow(row0);
0108                RowView rv1 = getRow(row1);
0109                if ((rv0 != null) && (rv1 != null)) {
0110                    int index0 = rv0.viewIndex;
0111                    int index1 = rv1.viewIndex;
0112                    int span = getOffset(Y_AXIS, index1)
0113                            - getOffset(Y_AXIS, index0)
0114                            + getSpan(Y_AXIS, index1);
0115                    return span;
0116                }
0117                return 0;
0118            }
0119
0120            /**
0121             * Fetches the span (height) of the given row.
0122             */
0123            public int getRowSpan(int row) {
0124                RowView rv = getRow(row);
0125                if (rv != null) {
0126                    return getSpan(Y_AXIS, rv.viewIndex);
0127                }
0128                return 0;
0129            }
0130
0131            RowView getRow(int row) {
0132                if (row < rows.size()) {
0133                    return (RowView) rows.elementAt(row);
0134                }
0135                return null;
0136            }
0137
0138            protected View getViewAtPoint(int x, int y, Rectangle alloc) {
0139                int n = getViewCount();
0140                View v = null;
0141                Rectangle allocation = new Rectangle();
0142                for (int i = 0; i < n; i++) {
0143                    allocation.setBounds(alloc);
0144                    childAllocation(i, allocation);
0145                    v = getView(i);
0146                    if (v instanceof  RowView) {
0147                        v = ((RowView) v).findViewAtPoint(x, y, allocation);
0148                        if (v != null) {
0149                            alloc.setBounds(allocation);
0150                            return v;
0151                        }
0152                    }
0153                }
0154                return super .getViewAtPoint(x, y, alloc);
0155            }
0156
0157            /**
0158             * Determines the number of columns occupied by
0159             * the table cell represented by given element.
0160             */
0161            protected int getColumnsOccupied(View v) {
0162                AttributeSet a = v.getElement().getAttributes();
0163
0164                if (a.isDefined(HTML.Attribute.COLSPAN)) {
0165                    String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
0166                    if (s != null) {
0167                        try {
0168                            return Integer.parseInt(s);
0169                        } catch (NumberFormatException nfe) {
0170                            // fall through to one column
0171                        }
0172                    }
0173                }
0174
0175                return 1;
0176            }
0177
0178            /**
0179             * Determines the number of rows occupied by
0180             * the table cell represented by given element.
0181             */
0182            protected int getRowsOccupied(View v) {
0183                AttributeSet a = v.getElement().getAttributes();
0184
0185                if (a.isDefined(HTML.Attribute.ROWSPAN)) {
0186                    String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
0187                    if (s != null) {
0188                        try {
0189                            return Integer.parseInt(s);
0190                        } catch (NumberFormatException nfe) {
0191                            // fall through to one row
0192                        }
0193                    }
0194                }
0195
0196                return 1;
0197            }
0198
0199            protected void invalidateGrid() {
0200                gridValid = false;
0201            }
0202
0203            protected StyleSheet getStyleSheet() {
0204                HTMLDocument doc = (HTMLDocument) getDocument();
0205                return doc.getStyleSheet();
0206            }
0207
0208            /**
0209             * Update the insets, which contain the caption if there
0210             * is a caption.
0211             */
0212            void updateInsets() {
0213                short top = (short) painter.getInset(TOP, this );
0214                short bottom = (short) painter.getInset(BOTTOM, this );
0215                if (captionIndex != -1) {
0216                    View caption = getView(captionIndex);
0217                    short h = (short) caption.getPreferredSpan(Y_AXIS);
0218                    AttributeSet a = caption.getAttributes();
0219                    Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);
0220                    if ((align != null) && (align.equals("bottom"))) {
0221                        bottom += h;
0222                    } else {
0223                        top += h;
0224                    }
0225                }
0226                setInsets(top, (short) painter.getInset(LEFT, this ), bottom,
0227                        (short) painter.getInset(RIGHT, this ));
0228            }
0229
0230            /**
0231             * Update any cached values that come from attributes.
0232             */
0233            protected void setPropertiesFromAttributes() {
0234                StyleSheet sheet = getStyleSheet();
0235                attr = sheet.getViewAttributes(this );
0236                painter = sheet.getBoxPainter(attr);
0237                if (attr != null) {
0238                    setInsets((short) painter.getInset(TOP, this ),
0239                            (short) painter.getInset(LEFT, this ),
0240                            (short) painter.getInset(BOTTOM, this ),
0241                            (short) painter.getInset(RIGHT, this ));
0242
0243                    CSS.LengthValue lv = (CSS.LengthValue) attr
0244                            .getAttribute(CSS.Attribute.BORDER_SPACING);
0245                    if (lv != null) {
0246                        cellSpacing = (int) lv.getValue();
0247                    } else {
0248                        cellSpacing = 0;
0249                    }
0250                    lv = (CSS.LengthValue) attr
0251                            .getAttribute(CSS.Attribute.BORDER_TOP_WIDTH);
0252                    if (lv != null) {
0253                        borderWidth = (int) lv.getValue();
0254                    } else {
0255                        borderWidth = 0;
0256                    }
0257
0258                }
0259            }
0260
0261            /**
0262             * Fill in the grid locations that are placeholders
0263             * for multi-column, multi-row, and missing grid
0264             * locations.
0265             */
0266            void updateGrid() {
0267                if (!gridValid) {
0268                    relativeCells = false;
0269                    multiRowCells = false;
0270
0271                    // determine which views are table rows and clear out
0272                    // grid points marked filled.
0273                    captionIndex = -1;
0274                    rows.removeAllElements();
0275                    int n = getViewCount();
0276                    for (int i = 0; i < n; i++) {
0277                        View v = getView(i);
0278                        if (v instanceof  RowView) {
0279                            rows.addElement(v);
0280                            RowView rv = (RowView) v;
0281                            rv.clearFilledColumns();
0282                            rv.rowIndex = rows.size() - 1;
0283                            rv.viewIndex = i;
0284                        } else {
0285                            Object o = v.getElement().getAttributes()
0286                                    .getAttribute(StyleConstants.NameAttribute);
0287                            if (o instanceof  HTML.Tag) {
0288                                HTML.Tag kind = (HTML.Tag) o;
0289                                if (kind == HTML.Tag.CAPTION) {
0290                                    captionIndex = i;
0291                                }
0292                            }
0293                        }
0294                    }
0295
0296                    int maxColumns = 0;
0297                    int nrows = rows.size();
0298                    for (int row = 0; row < nrows; row++) {
0299                        RowView rv = getRow(row);
0300                        int col = 0;
0301                        for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
0302                            View cv = rv.getView(cell);
0303                            if (!relativeCells) {
0304                                AttributeSet a = cv.getAttributes();
0305                                CSS.LengthValue lv = (CSS.LengthValue) a
0306                                        .getAttribute(CSS.Attribute.WIDTH);
0307                                if ((lv != null) && (lv.isPercentage())) {
0308                                    relativeCells = true;
0309                                }
0310                            }
0311                            // advance to a free column
0312                            for (; rv.isFilled(col); col++)
0313                                ;
0314                            int rowSpan = getRowsOccupied(cv);
0315                            if (rowSpan > 1) {
0316                                multiRowCells = true;
0317                            }
0318                            int colSpan = getColumnsOccupied(cv);
0319                            if ((colSpan > 1) || (rowSpan > 1)) {
0320                                // fill in the overflow entries for this cell
0321                                int rowLimit = row + rowSpan;
0322                                int colLimit = col + colSpan;
0323                                for (int i = row; i < rowLimit; i++) {
0324                                    for (int j = col; j < colLimit; j++) {
0325                                        if (i != row || j != col) {
0326                                            addFill(i, j);
0327                                        }
0328                                    }
0329                                }
0330                                if (colSpan > 1) {
0331                                    col += colSpan - 1;
0332                                }
0333                            }
0334                        }
0335                        maxColumns = Math.max(maxColumns, col);
0336                    }
0337
0338                    // setup the column layout/requirements
0339                    columnSpans = new int[maxColumns];
0340                    columnOffsets = new int[maxColumns];
0341                    columnRequirements = new SizeRequirements[maxColumns];
0342                    for (int i = 0; i < maxColumns; i++) {
0343                        columnRequirements[i] = new SizeRequirements();
0344                        columnRequirements[i].maximum = Integer.MAX_VALUE;
0345                    }
0346                    gridValid = true;
0347                }
0348            }
0349
0350            /**
0351             * Mark a grid location as filled in for a cells overflow.
0352             */
0353            void addFill(int row, int col) {
0354                RowView rv = getRow(row);
0355                if (rv != null) {
0356                    rv.fillColumn(col);
0357                }
0358            }
0359
0360            /**
0361             * Layout the columns to fit within the given target span.
0362             *
0363             * @param targetSpan the given span for total of all the table
0364             *  columns
0365             * @param reqs the requirements desired for each column.  This
0366             *  is the column maximum of the cells minimum, preferred, and
0367             *  maximum requested span
0368             * @param spans the return value of how much to allocated to
0369             *  each column
0370             * @param offsets the return value of the offset from the
0371             *  origin for each column
0372             * @return the offset from the origin and the span for each column 
0373             *  in the offsets and spans parameters
0374             */
0375            protected void layoutColumns(int targetSpan, int[] offsets,
0376                    int[] spans, SizeRequirements[] reqs) {
0377                //clean offsets and spans
0378                Arrays.fill(offsets, 0);
0379                Arrays.fill(spans, 0);
0380                colIterator.setLayoutArrays(offsets, spans, targetSpan);
0381                CSS.calculateTiledLayout(colIterator, targetSpan);
0382            }
0383
0384            /**
0385             * Calculate the requirements for each column.  The calculation
0386             * is done as two passes over the table.  The table cells that
0387             * occupy a single column are scanned first to determine the
0388             * maximum of minimum, preferred, and maximum spans along the
0389             * give axis.  Table cells that span multiple columns are excluded
0390             * from the first pass.  A second pass is made to determine if
0391             * the cells that span multiple columns are satisfied.  If the
0392             * column requirements are not satisified, the needs of the 
0393             * multi-column cell is mixed into the existing column requirements.
0394             * The calculation of the multi-column distribution is based upon
0395             * the proportions of the existing column requirements and taking
0396             * into consideration any constraining maximums.
0397             */
0398            void calculateColumnRequirements(int axis) {
0399                // clean columnRequirements
0400                for (SizeRequirements req : columnRequirements) {
0401                    req.minimum = 0;
0402                    req.preferred = 0;
0403                    req.maximum = Integer.MAX_VALUE;
0404                }
0405                Container host = getContainer();
0406                if (host != null) {
0407                    if (host instanceof  JTextComponent) {
0408                        skipComments = !((JTextComponent) host).isEditable();
0409                    } else {
0410                        skipComments = true;
0411                    }
0412                }
0413                // pass 1 - single column cells
0414                boolean hasMultiColumn = false;
0415                int nrows = getRowCount();
0416                for (int i = 0; i < nrows; i++) {
0417                    RowView row = getRow(i);
0418                    int col = 0;
0419                    int ncells = row.getViewCount();
0420                    for (int cell = 0; cell < ncells; cell++) {
0421                        View cv = row.getView(cell);
0422                        if (skipComments && !(cv instanceof  CellView)) {
0423                            continue;
0424                        }
0425                        for (; row.isFilled(col); col++)
0426                            ; // advance to a free column
0427                        int rowSpan = getRowsOccupied(cv);
0428                        int colSpan = getColumnsOccupied(cv);
0429                        if (colSpan == 1) {
0430                            checkSingleColumnCell(axis, col, cv);
0431                        } else {
0432                            hasMultiColumn = true;
0433                            col += colSpan - 1;
0434                        }
0435                        col++;
0436                    }
0437                }
0438
0439                // pass 2 - multi-column cells
0440                if (hasMultiColumn) {
0441                    for (int i = 0; i < nrows; i++) {
0442                        RowView row = getRow(i);
0443                        int col = 0;
0444                        int ncells = row.getViewCount();
0445                        for (int cell = 0; cell < ncells; cell++) {
0446                            View cv = row.getView(cell);
0447                            if (skipComments && !(cv instanceof  CellView)) {
0448                                continue;
0449                            }
0450                            for (; row.isFilled(col); col++)
0451                                ; // advance to a free column
0452                            int colSpan = getColumnsOccupied(cv);
0453                            if (colSpan > 1) {
0454                                checkMultiColumnCell(axis, col, colSpan, cv);
0455                                col += colSpan - 1;
0456                            }
0457                            col++;
0458                        }
0459                    }
0460                }
0461            }
0462
0463            /**
0464             * check the requirements of a table cell that spans a single column.
0465             */
0466            void checkSingleColumnCell(int axis, int col, View v) {
0467                SizeRequirements req = columnRequirements[col];
0468                req.minimum = Math.max((int) v.getMinimumSpan(axis),
0469                        req.minimum);
0470                req.preferred = Math.max((int) v.getPreferredSpan(axis),
0471                        req.preferred);
0472            }
0473
0474            /**
0475             * check the requirements of a table cell that spans multiple
0476             * columns.
0477             */
0478            void checkMultiColumnCell(int axis, int col, int ncols, View v) {
0479                // calculate the totals
0480                long min = 0;
0481                long pref = 0;
0482                long max = 0;
0483                for (int i = 0; i < ncols; i++) {
0484                    SizeRequirements req = columnRequirements[col + i];
0485                    min += req.minimum;
0486                    pref += req.preferred;
0487                    max += req.maximum;
0488                }
0489
0490                // check if the minimum size needs adjustment.
0491                int cmin = (int) v.getMinimumSpan(axis);
0492                if (cmin > min) {
0493                    /*
0494                     * the columns that this cell spans need adjustment to fit
0495                     * this table cell.... calculate the adjustments.
0496                     */
0497                    SizeRequirements[] reqs = new SizeRequirements[ncols];
0498                    for (int i = 0; i < ncols; i++) {
0499                        reqs[i] = columnRequirements[col + i];
0500                    }
0501                    int[] spans = new int[ncols];
0502                    int[] offsets = new int[ncols];
0503                    SizeRequirements.calculateTiledPositions(cmin, null, reqs,
0504                            offsets, spans);
0505                    // apply the adjustments
0506                    for (int i = 0; i < ncols; i++) {
0507                        SizeRequirements req = reqs[i];
0508                        req.minimum = Math.max(spans[i], req.minimum);
0509                        req.preferred = Math.max(req.minimum, req.preferred);
0510                        req.maximum = Math.max(req.preferred, req.maximum);
0511                    }
0512                }
0513
0514                // check if the preferred size needs adjustment.
0515                int cpref = (int) v.getPreferredSpan(axis);
0516                if (cpref > pref) {
0517                    /*
0518                     * the columns that this cell spans need adjustment to fit
0519                     * this table cell.... calculate the adjustments.
0520                     */
0521                    SizeRequirements[] reqs = new SizeRequirements[ncols];
0522                    for (int i = 0; i < ncols; i++) {
0523                        reqs[i] = columnRequirements[col + i];
0524                    }
0525                    int[] spans = new int[ncols];
0526                    int[] offsets = new int[ncols];
0527                    SizeRequirements.calculateTiledPositions(cpref, null, reqs,
0528                            offsets, spans);
0529                    // apply the adjustments
0530                    for (int i = 0; i < ncols; i++) {
0531                        SizeRequirements req = reqs[i];
0532                        req.preferred = Math.max(spans[i], req.preferred);
0533                        req.maximum = Math.max(req.preferred, req.maximum);
0534                    }
0535                }
0536
0537            }
0538
0539            // --- BoxView methods -----------------------------------------
0540
0541            /**
0542             * Calculate the requirements for the minor axis.  This is called by
0543             * the superclass whenever the requirements need to be updated (i.e.
0544             * a preferenceChanged was messaged through this view).  
0545             * <p>
0546             * This is implemented to calculate the requirements as the sum of the 
0547             * requirements of the columns and then adjust it if the 
0548             * CSS width or height attribute is specified and applicable to
0549             * the axis.
0550             */
0551            protected SizeRequirements calculateMinorAxisRequirements(int axis,
0552                    SizeRequirements r) {
0553                updateGrid();
0554
0555                // calculate column requirements for each column
0556                calculateColumnRequirements(axis);
0557
0558                // the requirements are the sum of the columns.
0559                if (r == null) {
0560                    r = new SizeRequirements();
0561                }
0562                long min = 0;
0563                long pref = 0;
0564                int n = columnRequirements.length;
0565                for (int i = 0; i < n; i++) {
0566                    SizeRequirements req = columnRequirements[i];
0567                    min += req.minimum;
0568                    pref += req.preferred;
0569                }
0570                int adjust = (n + 1) * cellSpacing + 2 * borderWidth;
0571                min += adjust;
0572                pref += adjust;
0573                r.minimum = (int) min;
0574                r.preferred = (int) pref;
0575                r.maximum = (int) pref;
0576
0577                AttributeSet attr = getAttributes();
0578                CSS.LengthValue cssWidth = (CSS.LengthValue) attr
0579                        .getAttribute(CSS.Attribute.WIDTH);
0580
0581                if (BlockView.spanSetFromAttributes(axis, r, cssWidth, null)) {
0582                    if (r.minimum < (int) min) {
0583                        // The user has requested a smaller size than is needed to
0584                        // show the table, override it.
0585                        r.maximum = r.minimum = r.preferred = (int) min;
0586                    }
0587                }
0588                totalColumnRequirements.minimum = r.minimum;
0589                totalColumnRequirements.preferred = r.preferred;
0590                totalColumnRequirements.maximum = r.maximum;
0591
0592                // set the alignment
0593                Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
0594                if (o != null) {
0595                    // set horizontal alignment
0596                    String ta = o.toString();
0597                    if (ta.equals("left")) {
0598                        r.alignment = 0;
0599                    } else if (ta.equals("center")) {
0600                        r.alignment = 0.5f;
0601                    } else if (ta.equals("right")) {
0602                        r.alignment = 1;
0603                    } else {
0604                        r.alignment = 0;
0605                    }
0606                } else {
0607                    r.alignment = 0;
0608                }
0609
0610                return r;
0611            }
0612
0613            /**
0614             * Calculate the requirements for the major axis.  This is called by
0615             * the superclass whenever the requirements need to be updated (i.e.
0616             * a preferenceChanged was messaged through this view).  
0617             * <p>
0618             * This is implemented to provide the superclass behavior adjusted for
0619             * multi-row table cells.
0620             */
0621            protected SizeRequirements calculateMajorAxisRequirements(int axis,
0622                    SizeRequirements r) {
0623                updateInsets();
0624                rowIterator.updateAdjustments();
0625                r = CSS.calculateTiledRequirements(rowIterator, r);
0626                r.maximum = r.preferred;
0627                return r;
0628            }
0629
0630            /**
0631             * Perform layout for the minor axis of the box (i.e. the
0632             * axis orthoginal to the axis that it represents).  The results 
0633             * of the layout should be placed in the given arrays which represent 
0634             * the allocations to the children along the minor axis.  This 
0635             * is called by the superclass whenever the layout needs to be 
0636             * updated along the minor axis.
0637             * <p>
0638             * This is implemented to call the 
0639             * <a href="#layoutColumns">layoutColumns</a> method, and then
0640             * forward to the superclass to actually carry out the layout
0641             * of the tables rows.
0642             *
0643             * @param targetSpan the total span given to the view, which
0644             *  whould be used to layout the children
0645             * @param axis the axis being layed out
0646             * @param offsets the offsets from the origin of the view for
0647             *  each of the child views.  This is a return value and is
0648             *  filled in by the implementation of this method
0649             * @param spans the span of each child view;  this is a return
0650             *  value and is filled in by the implementation of this method
0651             * @return the offset and span for each child view in the
0652             *  offsets and spans parameters
0653             */
0654            protected void layoutMinorAxis(int targetSpan, int axis,
0655                    int[] offsets, int[] spans) {
0656                // make grid is properly represented
0657                updateGrid();
0658
0659                // all of the row layouts are invalid, so mark them that way
0660                int n = getRowCount();
0661                for (int i = 0; i < n; i++) {
0662                    RowView row = getRow(i);
0663                    row.layoutChanged(axis);
0664                }
0665
0666                // calculate column spans
0667                layoutColumns(targetSpan, columnOffsets, columnSpans,
0668                        columnRequirements);
0669
0670                // continue normal layout
0671                super .layoutMinorAxis(targetSpan, axis, offsets, spans);
0672            }
0673
0674            /**
0675             * Perform layout for the major axis of the box (i.e. the
0676             * axis that it represents).  The results 
0677             * of the layout should be placed in the given arrays which represent 
0678             * the allocations to the children along the minor axis.  This 
0679             * is called by the superclass whenever the layout needs to be 
0680             * updated along the minor axis.
0681             * <p>
0682             * This method is where the layout of the table rows within the
0683             * table takes place.  This method is implemented to call the use 
0684             * the RowIterator and the CSS collapsing tile to layout 
0685             * with border spacing and border collapsing capabilities.
0686             *
0687             * @param targetSpan the total span given to the view, which
0688             *  whould be used to layout the children
0689             * @param axis the axis being layed out
0690             * @param offsets the offsets from the origin of the view for
0691             *  each of the child views; this is a return value and is
0692             *  filled in by the implementation of this method
0693             * @param spans the span of each child view; this is a return
0694             *  value and is filled in by the implementation of this method
0695             * @return the offset and span for each child view in the
0696             *  offsets and spans parameters
0697             */
0698            protected void layoutMajorAxis(int targetSpan, int axis,
0699                    int[] offsets, int[] spans) {
0700                rowIterator.setLayoutArrays(offsets, spans);
0701                CSS.calculateTiledLayout(rowIterator, targetSpan);
0702
0703                if (captionIndex != -1) {
0704                    // place the caption
0705                    View caption = getView(captionIndex);
0706                    int h = (int) caption.getPreferredSpan(Y_AXIS);
0707                    spans[captionIndex] = h;
0708                    short boxBottom = (short) painter.getInset(BOTTOM, this );
0709                    if (boxBottom != getBottomInset()) {
0710                        offsets[captionIndex] = targetSpan + boxBottom;
0711                    } else {
0712                        offsets[captionIndex] = -getTopInset();
0713                    }
0714                }
0715            }
0716
0717            /**
0718             * Fetches the child view that represents the given position in
0719             * the model.  This is implemented to walk through the children
0720             * looking for a range that contains the given position.  In this
0721             * view the children do not necessarily have a one to one mapping 
0722             * with the child elements.
0723             *
0724             * @param pos  the search position >= 0
0725             * @param a  the allocation to the table on entry, and the
0726             *   allocation of the view containing the position on exit
0727             * @return  the view representing the given position, or 
0728             *   null if there isn't one
0729             */
0730            protected View getViewAtPosition(int pos, Rectangle a) {
0731                int n = getViewCount();
0732                for (int i = 0; i < n; i++) {
0733                    View v = getView(i);
0734                    int p0 = v.getStartOffset();
0735                    int p1 = v.getEndOffset();
0736                    if ((pos >= p0) && (pos < p1)) {
0737                        // it's in this view.
0738                        if (a != null) {
0739                            childAllocation(i, a);
0740                        }
0741                        return v;
0742                    }
0743                }
0744                if (pos == getEndOffset()) {
0745                    View v = getView(n - 1);
0746                    if (a != null) {
0747                        this .childAllocation(n - 1, a);
0748                    }
0749                    return v;
0750                }
0751                return null;
0752            }
0753
0754            // --- View methods ---------------------------------------------
0755
0756            /**
0757             * Fetches the attributes to use when rendering.  This is
0758             * implemented to multiplex the attributes specified in the
0759             * model with a StyleSheet.
0760             */
0761            public AttributeSet getAttributes() {
0762                if (attr == null) {
0763                    StyleSheet sheet = getStyleSheet();
0764                    attr = sheet.getViewAttributes(this );
0765                }
0766                return attr;
0767            }
0768
0769            /**
0770             * Renders using the given rendering surface and area on that
0771             * surface.  This is implemented to delegate to the css box
0772             * painter to paint the border and background prior to the 
0773             * interior.  The superclass culls rendering the children
0774             * that don't directly intersect the clip and the row may
0775             * have cells hanging from a row above in it.  The table
0776             * does not use the superclass rendering behavior and instead
0777             * paints all of the rows and lets the rows cull those 
0778             * cells not intersecting the clip region.
0779             *
0780             * @param g the rendering surface to use
0781             * @param allocation the allocated region to render into
0782             * @see View#paint
0783             */
0784            public void paint(Graphics g, Shape allocation) {
0785                // paint the border 
0786                Rectangle a = allocation.getBounds();
0787                setSize(a.width, a.height);
0788                if (captionIndex != -1) {
0789                    // adjust the border for the caption
0790                    short top = (short) painter.getInset(TOP, this );
0791                    short bottom = (short) painter.getInset(BOTTOM, this );
0792                    if (top != getTopInset()) {
0793                        int h = getTopInset() - top;
0794                        a.y += h;
0795                        a.height -= h;
0796                    } else {
0797                        a.height -= getBottomInset() - bottom;
0798                    }
0799                }
0800                painter.paint(g, a.x, a.y, a.width, a.height, this );
0801                // paint interior
0802                int n = getViewCount();
0803                for (int i = 0; i < n; i++) {
0804                    View v = getView(i);
0805                    v.paint(g, getChildAllocation(i, allocation));
0806                }
0807                //super.paint(g, a);
0808            }
0809
0810            /**
0811             * Establishes the parent view for this view.  This is
0812             * guaranteed to be called before any other methods if the
0813             * parent view is functioning properly.
0814             * <p> 
0815             * This is implemented
0816             * to forward to the superclass as well as call the
0817             * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
0818             * method to set the paragraph properties from the css
0819             * attributes.  The call is made at this time to ensure
0820             * the ability to resolve upward through the parents 
0821             * view attributes.
0822             *
0823             * @param parent the new parent, or null if the view is
0824             *  being removed from a parent it was previously added
0825             *  to
0826             */
0827            public void setParent(View parent) {
0828                super .setParent(parent);
0829                if (parent != null) {
0830                    setPropertiesFromAttributes();
0831                }
0832            }
0833
0834            /**
0835             * Fetches the ViewFactory implementation that is feeding
0836             * the view hierarchy.  
0837             * This replaces the ViewFactory with an implementation that
0838             * calls through to the createTableRow and createTableCell
0839             * methods.   If the element given to the factory isn't a
0840             * table row or cell, the request is delegated to the factory
0841             * produced by the superclass behavior.
0842             *
0843             * @return the factory, null if none
0844             */
0845            public ViewFactory getViewFactory() {
0846                return this ;
0847            }
0848
0849            /**
0850             * Gives notification that something was inserted into 
0851             * the document in a location that this view is responsible for. 
0852             * This replaces the ViewFactory with an implementation that
0853             * calls through to the createTableRow and createTableCell
0854             * methods.   If the element given to the factory isn't a
0855             * table row or cell, the request is delegated to the factory
0856             * passed as an argument.
0857             *
0858             * @param e the change information from the associated document
0859             * @param a the current allocation of the view
0860             * @param f the factory to use to rebuild if the view has children
0861             * @see View#insertUpdate
0862             */
0863            public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0864                super .insertUpdate(e, a, this );
0865            }
0866
0867            /**
0868             * Gives notification that something was removed from the document
0869             * in a location that this view is responsible for.
0870             * This replaces the ViewFactory with an implementation that
0871             * calls through to the createTableRow and createTableCell
0872             * methods.   If the element given to the factory isn't a
0873             * table row or cell, the request is delegated to the factory
0874             * passed as an argument.
0875             *
0876             * @param e the change information from the associated document
0877             * @param a the current allocation of the view
0878             * @param f the factory to use to rebuild if the view has children
0879             * @see View#removeUpdate
0880             */
0881            public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0882                super .removeUpdate(e, a, this );
0883            }
0884
0885            /**
0886             * Gives notification from the document that attributes were changed
0887             * in a location that this view is responsible for.
0888             * This replaces the ViewFactory with an implementation that
0889             * calls through to the createTableRow and createTableCell
0890             * methods.   If the element given to the factory isn't a
0891             * table row or cell, the request is delegated to the factory
0892             * passed as an argument.
0893             *
0894             * @param e the change information from the associated document
0895             * @param a the current allocation of the view
0896             * @param f the factory to use to rebuild if the view has children
0897             * @see View#changedUpdate
0898             */
0899            public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0900                super .changedUpdate(e, a, this );
0901            }
0902
0903            protected void forwardUpdate(DocumentEvent.ElementChange ec,
0904                    DocumentEvent e, Shape a, ViewFactory f) {
0905                super .forwardUpdate(ec, e, a, f);
0906                // A change in any of the table cells usually effects the whole table,
0907                // so redraw it all!
0908                if (a != null) {
0909                    Component c = getContainer();
0910                    if (c != null) {
0911                        Rectangle alloc = (a instanceof  Rectangle) ? (Rectangle) a
0912                                : a.getBounds();
0913                        c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
0914                    }
0915                }
0916            }
0917
0918            /**
0919             * Change the child views.  This is implemented to
0920             * provide the superclass behavior and invalidate the
0921             * grid so that rows and columns will be recalculated.
0922             */
0923            public void replace(int offset, int length, View[] views) {
0924                super .replace(offset, length, views);
0925                invalidateGrid();
0926            }
0927
0928            // --- ViewFactory methods ------------------------------------------
0929
0930            /**
0931             * The table itself acts as a factory for the various 
0932             * views that actually represent pieces of the table.
0933             * All other factory activity is delegated to the factory
0934             * returned by the parent of the table.
0935             */
0936            public View create(Element elem) {
0937                Object o = elem.getAttributes().getAttribute(
0938                        StyleConstants.NameAttribute);
0939                if (o instanceof  HTML.Tag) {
0940                    HTML.Tag kind = (HTML.Tag) o;
0941                    if (kind == HTML.Tag.TR) {
0942                        return createTableRow(elem);
0943                    } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
0944                        return new CellView(elem);
0945                    } else if (kind == HTML.Tag.CAPTION) {
0946                        return new javax.swing.text.html.ParagraphView(elem);
0947                    }
0948                }
0949                // default is to delegate to the normal factory
0950                View p = getParent();
0951                if (p != null) {
0952                    ViewFactory f = p.getViewFactory();
0953                    if (f != null) {
0954                        return f.create(elem);
0955                    }
0956                }
0957                return null;
0958            }
0959
0960            // ---- variables ----------------------------------------------------
0961
0962            private AttributeSet attr;
0963            private StyleSheet.BoxPainter painter;
0964
0965            private int cellSpacing;
0966            private int borderWidth;
0967
0968            /**
0969             * The index of the caption view if there is a caption.
0970             * This has a value of -1 if there is no caption.  The
0971             * caption lives in the inset area of the table, and is
0972             * updated with each time the grid is recalculated.
0973             */
0974            private int captionIndex;
0975
0976            /**
0977             * Do any of the table cells contain a relative size
0978             * specification?  This is updated with each call to
0979             * updateGrid().  If this is true, the ColumnIterator
0980             * will do extra work to calculate relative cell 
0981             * specifications.
0982             */
0983            private boolean relativeCells;
0984
0985            /**
0986             * Do any of the table cells span multiple rows?  If
0987             * true, the RowRequirementIterator will do additional
0988             * work to adjust the requirements of rows spanned by
0989             * a single table cell.  This is updated with each call to
0990             * updateGrid().
0991             */
0992            private boolean multiRowCells;
0993
0994            int[] columnSpans;
0995            int[] columnOffsets;
0996            /**
0997             * SizeRequirements for all the columns.
0998             */
0999            SizeRequirements totalColumnRequirements;
1000            SizeRequirements[] columnRequirements;
1001
1002            RowIterator rowIterator = new RowIterator();
1003            ColumnIterator colIterator = new ColumnIterator();
1004
1005            Vector rows;
1006
1007            // whether to display comments inside table or not.
1008            boolean skipComments = false;
1009
1010            boolean gridValid;
1011            static final private BitSet EMPTY = new BitSet();
1012
1013            class ColumnIterator implements  CSS.LayoutIterator {
1014
1015                /**
1016                 * Disable percentage adjustments which should only apply
1017                 * when calculating layout, not requirements.
1018                 */
1019                void disablePercentages() {
1020                    percentages = null;
1021                }
1022
1023                /**
1024                 * Update percentage adjustments if they are needed.
1025                 */
1026                private void updatePercentagesAndAdjustmentWeights(int span) {
1027                    adjustmentWeights = new int[columnRequirements.length];
1028                    for (int i = 0; i < columnRequirements.length; i++) {
1029                        adjustmentWeights[i] = 0;
1030                    }
1031                    if (relativeCells) {
1032                        percentages = new int[columnRequirements.length];
1033                    } else {
1034                        percentages = null;
1035                    }
1036                    int nrows = getRowCount();
1037                    for (int rowIndex = 0; rowIndex < nrows; rowIndex++) {
1038                        RowView row = getRow(rowIndex);
1039                        int col = 0;
1040                        int ncells = row.getViewCount();
1041                        for (int cell = 0; cell < ncells; cell++, col++) {
1042                            View cv = row.getView(cell);
1043                            for (; row.isFilled(col); col++)
1044                                ; // advance to a free column
1045                            int rowSpan = getRowsOccupied(cv);
1046                            int colSpan = getColumnsOccupied(cv);
1047                            AttributeSet a = cv.getAttributes();
1048                            CSS.LengthValue lv = (CSS.LengthValue) a
1049                                    .getAttribute(CSS.Attribute.WIDTH);
1050                            if (lv != null) {
1051                                int len = (int) (lv.getValue(span) / colSpan + 0.5f);
1052                                for (int i = 0; i < colSpan; i++) {
1053                                    if (lv.isPercentage()) {
1054                                        // add a percentage requirement
1055                                        percentages[col + i] = Math.max(
1056                                                percentages[col + i], len);
1057                                        adjustmentWeights[col + i] = Math.max(
1058                                                adjustmentWeights[col + i],
1059                                                WorstAdjustmentWeight);
1060                                    } else {
1061                                        adjustmentWeights[col + i] = Math.max(
1062                                                adjustmentWeights[col + i],
1063                                                WorstAdjustmentWeight - 1);
1064                                    }
1065                                }
1066                            }
1067                            col += colSpan - 1;
1068                        }
1069                    }
1070                }
1071
1072                /**
1073                 * Set the layout arrays to use for holding layout results
1074                 */
1075                public void setLayoutArrays(int offsets[], int spans[],
1076                        int targetSpan) {
1077                    this .offsets = offsets;
1078                    this .spans = spans;
1079                    updatePercentagesAndAdjustmentWeights(targetSpan);
1080                }
1081
1082                // --- RequirementIterator methods -------------------
1083
1084                public int getCount() {
1085                    return columnRequirements.length;
1086                }
1087
1088                public void setIndex(int i) {
1089                    col = i;
1090                }
1091
1092                public void setOffset(int offs) {
1093                    offsets[col] = offs;
1094                }
1095
1096                public int getOffset() {
1097                    return offsets[col];
1098                }
1099
1100                public void setSpan(int span) {
1101                    spans[col] = span;
1102                }
1103
1104                public int getSpan() {
1105                    return spans[col];
1106                }
1107
1108                public float getMinimumSpan(float parentSpan) {
1109                    // do not care for percentages, since min span can't 
1110                    // be less than columnRequirements[col].minimum,
1111                    // but can be less than percentage value.
1112                    return columnRequirements[col].minimum;
1113                }
1114
1115                public float getPreferredSpan(float parentSpan) {
1116                    if ((percentages != null) && (percentages[col] != 0)) {
1117                        return Math.max(percentages[col],
1118                                columnRequirements[col].minimum);
1119                    }
1120                    return columnRequirements[col].preferred;
1121                }
1122
1123                public float getMaximumSpan(float parentSpan) {
1124                    return columnRequirements[col].maximum;
1125                }
1126
1127                public float getBorderWidth() {
1128                    return borderWidth;
1129                }
1130
1131                public float getLeadingCollapseSpan() {
1132                    return cellSpacing;
1133                }
1134
1135                public float getTrailingCollapseSpan() {
1136                    return cellSpacing;
1137                }
1138
1139                public int getAdjustmentWeight() {
1140                    return adjustmentWeights[col];
1141                }
1142
1143                /**
1144                 * Current column index
1145                 */
1146                private int col;
1147
1148                /**
1149                 * percentage values (may be null since there
1150                 * might not be any).
1151                 */
1152                private int[] percentages;
1153
1154                private int[] adjustmentWeights;
1155
1156                private int[] offsets;
1157                private int[] spans;
1158            }
1159
1160            class RowIterator implements  CSS.LayoutIterator {
1161
1162                RowIterator() {
1163                }
1164
1165                void updateAdjustments() {
1166                    int axis = Y_AXIS;
1167                    if (multiRowCells) {
1168                        // adjust requirements of multi-row cells
1169                        int n = getRowCount();
1170                        adjustments = new int[n];
1171                        for (int i = 0; i < n; i++) {
1172                            RowView rv = getRow(i);
1173                            if (rv.multiRowCells == true) {
1174                                int ncells = rv.getViewCount();
1175                                for (int j = 0; j < ncells; j++) {
1176                                    View v = rv.getView(j);
1177                                    int nrows = getRowsOccupied(v);
1178                                    if (nrows > 1) {
1179                                        int spanNeeded = (int) v
1180                                                .getPreferredSpan(axis);
1181                                        adjustMultiRowSpan(spanNeeded, nrows, i);
1182                                    }
1183                                }
1184                            }
1185                        }
1186                    } else {
1187                        adjustments = null;
1188                    }
1189                }
1190
1191                /**
1192                 * Fixup preferences to accomodate a multi-row table cell
1193                 * if not already covered by existing preferences.  This is
1194                 * a no-op if not all of the rows needed (to do this check/fixup)
1195                 * have arrived yet.
1196                 */
1197                void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) {
1198                    if ((rowIndex + nrows) > getCount()) {
1199                        // rows are missing (could be a bad rowspan specification)
1200                        // or not all the rows have arrived.  Do the best we can with
1201                        // the current set of rows.
1202                        nrows = getCount() - rowIndex;
1203                        if (nrows < 1) {
1204                            return;
1205                        }
1206                    }
1207                    int span = 0;
1208                    for (int i = 0; i < nrows; i++) {
1209                        RowView rv = getRow(rowIndex + i);
1210                        span += rv.getPreferredSpan(Y_AXIS);
1211                    }
1212                    if (spanNeeded > span) {
1213                        int adjust = (spanNeeded - span);
1214                        int rowAdjust = adjust / nrows;
1215                        int firstAdjust = rowAdjust
1216                                + (adjust - (rowAdjust * nrows));
1217                        RowView rv = getRow(rowIndex);
1218                        adjustments[rowIndex] = Math.max(adjustments[rowIndex],
1219                                firstAdjust);
1220                        for (int i = 1; i < nrows; i++) {
1221                            adjustments[rowIndex + i] = Math.max(
1222                                    adjustments[rowIndex + i], rowAdjust);
1223                        }
1224                    }
1225                }
1226
1227                void setLayoutArrays(int[] offsets, int[] spans) {
1228                    this .offsets = offsets;
1229                    this .spans = spans;
1230                }
1231
1232                // --- RequirementIterator methods -------------------
1233
1234                public void setOffset(int offs) {
1235                    RowView rv = getRow(row);
1236                    if (rv != null) {
1237                        offsets[rv.viewIndex] = offs;
1238                    }
1239                }
1240
1241                public int getOffset() {
1242                    RowView rv = getRow(row);
1243                    if (rv != null) {
1244                        return offsets[rv.viewIndex];
1245                    }
1246                    return 0;
1247                }
1248
1249                public void setSpan(int span) {
1250                    RowView rv = getRow(row);
1251                    if (rv != null) {
1252                        spans[rv.viewIndex] = span;
1253                    }
1254                }
1255
1256                public int getSpan() {
1257                    RowView rv = getRow(row);
1258                    if (rv != null) {
1259                        return spans[rv.viewIndex];
1260                    }
1261                    return 0;
1262                }
1263
1264                public int getCount() {
1265                    return rows.size();
1266                }
1267
1268                public void setIndex(int i) {
1269                    row = i;
1270                }
1271
1272                public float getMinimumSpan(float parentSpan) {
1273                    return getPreferredSpan(parentSpan);
1274                }
1275
1276                public float getPreferredSpan(float parentSpan) {
1277                    RowView rv = getRow(row);
1278                    if (rv != null) {
1279                        int adjust = (adjustments != null) ? adjustments[row]
1280                                : 0;
1281                        return rv.getPreferredSpan(TableView.this .getAxis())
1282                                + adjust;
1283                    }
1284                    return 0;
1285                }
1286
1287                public float getMaximumSpan(float parentSpan) {
1288                    return getPreferredSpan(parentSpan);
1289                }
1290
1291                public float getBorderWidth() {
1292                    return borderWidth;
1293                }
1294
1295                public float getLeadingCollapseSpan() {
1296                    return cellSpacing;
1297                }
1298
1299                public float getTrailingCollapseSpan() {
1300                    return cellSpacing;
1301                }
1302
1303                public int getAdjustmentWeight() {
1304                    return 0;
1305                }
1306
1307                /**
1308                 * Current row index
1309                 */
1310                private int row;
1311
1312                /**
1313                 * Adjustments to the row requirements to handle multi-row
1314                 * table cells.  
1315                 */
1316                private int[] adjustments;
1317
1318                private int[] offsets;
1319                private int[] spans;
1320            }
1321
1322            /**
1323             * View of a row in a row-centric table.
1324             */
1325            public class RowView extends BoxView {
1326
1327                /**
1328                 * Constructs a TableView for the given element.
1329                 *
1330                 * @param elem the element that this view is responsible for
1331                 */
1332                public RowView(Element elem) {
1333                    super (elem, View.X_AXIS);
1334                    fillColumns = new BitSet();
1335                    RowView.this .setPropertiesFromAttributes();
1336                }
1337
1338                void clearFilledColumns() {
1339                    fillColumns.and(EMPTY);
1340                }
1341
1342                void fillColumn(int col) {
1343                    fillColumns.set(col);
1344                }
1345
1346                boolean isFilled(int col) {
1347                    return fillColumns.get(col);
1348                }
1349
1350                /**
1351                 * The number of columns present in this row.
1352                 */
1353                int getColumnCount() {
1354                    int nfill = 0;
1355                    int n = fillColumns.size();
1356                    for (int i = 0; i < n; i++) {
1357                        if (fillColumns.get(i)) {
1358                            nfill++;
1359                        }
1360                    }
1361                    return getViewCount() + nfill;
1362                }
1363
1364                /**
1365                 * Fetches the attributes to use when rendering.  This is
1366                 * implemented to multiplex the attributes specified in the
1367                 * model with a StyleSheet.
1368                 */
1369                public AttributeSet getAttributes() {
1370                    return attr;
1371                }
1372
1373                View findViewAtPoint(int x, int y, Rectangle alloc) {
1374                    int n = getViewCount();
1375                    for (int i = 0; i < n; i++) {
1376                        if (getChildAllocation(i, alloc).contains(x, y)) {
1377                            childAllocation(i, alloc);
1378                            return getView(i);
1379                        }
1380                    }
1381                    return null;
1382                }
1383
1384                protected StyleSheet getStyleSheet() {
1385                    HTMLDocument doc = (HTMLDocument) getDocument();
1386                    return doc.getStyleSheet();
1387                }
1388
1389                /**
1390                 * This is called by a child to indicate its 
1391                 * preferred span has changed.  This is implemented to
1392                 * execute the superclass behavior and well as try to
1393                 * determine if a row with a multi-row cell hangs across
1394                 * this row.  If a multi-row cell covers this row it also
1395                 * needs to propagate a preferenceChanged so that it will
1396                 * recalculate the multi-row cell.
1397                 *
1398                 * @param child the child view
1399                 * @param width true if the width preference should change
1400                 * @param height true if the height preference should change
1401                 */
1402                public void preferenceChanged(View child, boolean width,
1403                        boolean height) {
1404                    super .preferenceChanged(child, width, height);
1405                    if (TableView.this .multiRowCells && height) {
1406                        for (int i = rowIndex - 1; i >= 0; i--) {
1407                            RowView rv = TableView.this .getRow(i);
1408                            if (rv.multiRowCells) {
1409                                rv.preferenceChanged(null, false, true);
1410                                break;
1411                            }
1412                        }
1413                    }
1414                }
1415
1416                // The major axis requirements for a row are dictated by the column
1417                // requirements. These methods use the value calculated by
1418                // TableView.
1419                protected SizeRequirements calculateMajorAxisRequirements(
1420                        int axis, SizeRequirements r) {
1421                    SizeRequirements req = new SizeRequirements();
1422                    req.minimum = totalColumnRequirements.minimum;
1423                    req.maximum = totalColumnRequirements.maximum;
1424                    req.preferred = totalColumnRequirements.preferred;
1425                    req.alignment = 0f;
1426                    return req;
1427                }
1428
1429                public float getMinimumSpan(int axis) {
1430                    float value;
1431
1432                    if (axis == View.X_AXIS) {
1433                        value = totalColumnRequirements.minimum
1434                                + getLeftInset() + getRightInset();
1435                    } else {
1436                        value = super .getMinimumSpan(axis);
1437                    }
1438                    return value;
1439                }
1440
1441                public float getMaximumSpan(int axis) {
1442                    float value;
1443
1444                    if (axis == View.X_AXIS) {
1445                        // We're flexible.
1446                        value = (float) Integer.MAX_VALUE;
1447                    } else {
1448                        value = super .getMaximumSpan(axis);
1449                    }
1450                    return value;
1451                }
1452
1453                public float getPreferredSpan(int axis) {
1454                    float value;
1455
1456                    if (axis == View.X_AXIS) {
1457                        value = totalColumnRequirements.preferred
1458                                + getLeftInset() + getRightInset();
1459                    } else {
1460                        value = super .getPreferredSpan(axis);
1461                    }
1462                    return value;
1463                }
1464
1465                public void changedUpdate(DocumentEvent e, Shape a,
1466                        ViewFactory f) {
1467                    super .changedUpdate(e, a, f);
1468                    int pos = e.getOffset();
1469                    if (pos <= getStartOffset()
1470                            && (pos + e.getLength()) >= getEndOffset()) {
1471                        RowView.this .setPropertiesFromAttributes();
1472                    }
1473                }
1474
1475                /**
1476                 * Renders using the given rendering surface and area on that
1477                 * surface.  This is implemented to delegate to the css box
1478                 * painter to paint the border and background prior to the 
1479                 * interior.
1480                 *
1481                 * @param g the rendering surface to use
1482                 * @param allocation the allocated region to render into
1483                 * @see View#paint
1484                 */
1485                public void paint(Graphics g, Shape allocation) {
1486                    Rectangle a = (Rectangle) allocation;
1487                    painter.paint(g, a.x, a.y, a.width, a.height, this );
1488                    super .paint(g, a);
1489                }
1490
1491                /**
1492                 * Change the child views.  This is implemented to
1493                 * provide the superclass behavior and invalidate the
1494                 * grid so that rows and columns will be recalculated.
1495                 */
1496                public void replace(int offset, int length, View[] views) {
1497                    super .replace(offset, length, views);
1498                    invalidateGrid();
1499                }
1500
1501                /**
1502                 * Calculate the height requirements of the table row.  The
1503                 * requirements of multi-row cells are not considered for this
1504                 * calculation.  The table itself will check and adjust the row
1505                 * requirements for all the rows that have multi-row cells spanning
1506                 * them.  This method updates the multi-row flag that indicates that
1507                 * this row and rows below need additional consideration.
1508                 */
1509                protected SizeRequirements calculateMinorAxisRequirements(
1510                        int axis, SizeRequirements r) {
1511                    //	    return super.calculateMinorAxisRequirements(axis, r);
1512                    long min = 0;
1513                    long pref = 0;
1514                    long max = 0;
1515                    multiRowCells = false;
1516                    int n = getViewCount();
1517                    for (int i = 0; i < n; i++) {
1518                        View v = getView(i);
1519                        if (getRowsOccupied(v) > 1) {
1520                            multiRowCells = true;
1521                            max = Math.max((int) v.getMaximumSpan(axis), max);
1522                        } else {
1523                            min = Math.max((int) v.getMinimumSpan(axis), min);
1524                            pref = Math.max((int) v.getPreferredSpan(axis),
1525                                    pref);
1526                            max = Math.max((int) v.getMaximumSpan(axis), max);
1527                        }
1528                    }
1529
1530                    if (r == null) {
1531                        r = new SizeRequirements();
1532                        r.alignment = 0.5f;
1533                    }
1534                    r.preferred = (int) pref;
1535                    r.minimum = (int) min;
1536                    r.maximum = (int) max;
1537                    return r;
1538                }
1539
1540                /**
1541                 * Perform layout for the major axis of the box (i.e. the
1542                 * axis that it represents).  The results of the layout should
1543                 * be placed in the given arrays which represent the allocations
1544                 * to the children along the major axis.  
1545                 * <p>
1546                 * This is re-implemented to give each child the span of the column 
1547                 * width for the table, and to give cells that span multiple columns 
1548                 * the multi-column span.
1549                 *
1550                 * @param targetSpan the total span given to the view, which
1551                 *  whould be used to layout the children
1552                 * @param axis the axis being layed out
1553                 * @param offsets the offsets from the origin of the view for
1554                 *  each of the child views; this is a return value and is
1555                 *  filled in by the implementation of this method
1556                 * @param spans the span of each child view; this is a return
1557                 *  value and is filled in by the implementation of this method
1558                 * @return the offset and span for each child view in the
1559                 *  offsets and spans parameters
1560                 */
1561                protected void layoutMajorAxis(int targetSpan, int axis,
1562                        int[] offsets, int[] spans) {
1563                    int col = 0;
1564                    int ncells = getViewCount();
1565                    for (int cell = 0; cell < ncells; cell++) {
1566                        View cv = getView(cell);
1567                        if (skipComments && !(cv instanceof  CellView)) {
1568                            continue;
1569                        }
1570                        for (; isFilled(col); col++)
1571                            ; // advance to a free column
1572                        int colSpan = getColumnsOccupied(cv);
1573                        spans[cell] = columnSpans[col];
1574                        offsets[cell] = columnOffsets[col];
1575                        if (colSpan > 1) {
1576                            int n = columnSpans.length;
1577                            for (int j = 1; j < colSpan; j++) {
1578                                // Because the table may be only partially formed, some
1579                                // of the columns may not yet exist.  Therefore we check
1580                                // the bounds.
1581                                if ((col + j) < n) {
1582                                    spans[cell] += columnSpans[col + j];
1583                                    spans[cell] += cellSpacing;
1584                                }
1585                            }
1586                            col += colSpan - 1;
1587                        }
1588                        col++;
1589                    }
1590                }
1591
1592                /**
1593                 * Perform layout for the minor axis of the box (i.e. the
1594                 * axis orthoginal to the axis that it represents).  The results 
1595                 * of the layout should be placed in the given arrays which represent 
1596                 * the allocations to the children along the minor axis.  This 
1597                 * is called by the superclass whenever the layout needs to be 
1598                 * updated along the minor axis.
1599                 * <p>
1600                 * This is implemented to delegate to the superclass, then adjust
1601                 * the span for any cell that spans multiple rows.
1602                 *
1603                 * @param targetSpan the total span given to the view, which
1604                 *  whould be used to layout the children
1605                 * @param axis the axis being layed out
1606                 * @param offsets the offsets from the origin of the view for
1607                 *  each of the child views; this is a return value and is
1608                 *  filled in by the implementation of this method
1609                 * @param spans the span of each child view; this is a return
1610                 *  value and is filled in by the implementation of this method
1611                 * @return the offset and span for each child view in the
1612                 *  offsets and spans parameters
1613                 */
1614                protected void layoutMinorAxis(int targetSpan, int axis,
1615                        int[] offsets, int[] spans) {
1616                    super .layoutMinorAxis(targetSpan, axis, offsets, spans);
1617                    int col = 0;
1618                    int ncells = getViewCount();
1619                    for (int cell = 0; cell < ncells; cell++, col++) {
1620                        View cv = getView(cell);
1621                        for (; isFilled(col); col++)
1622                            ; // advance to a free column
1623                        int colSpan = getColumnsOccupied(cv);
1624                        int rowSpan = getRowsOccupied(cv);
1625                        if (rowSpan > 1) {
1626
1627                            int row0 = rowIndex;
1628                            int row1 = Math.min(rowIndex + rowSpan - 1,
1629                                    getRowCount() - 1);
1630                            spans[cell] = getMultiRowSpan(row0, row1);
1631                        }
1632                        if (colSpan > 1) {
1633                            col += colSpan - 1;
1634                        }
1635                    }
1636                }
1637
1638                /**
1639                 * Determines the resizability of the view along the
1640                 * given axis.  A value of 0 or less is not resizable.
1641                 *
1642                 * @param axis may be either View.X_AXIS or View.Y_AXIS
1643                 * @return the resize weight
1644                 * @exception IllegalArgumentException for an invalid axis
1645                 */
1646                public int getResizeWeight(int axis) {
1647                    return 1;
1648                }
1649
1650                /**
1651                 * Fetches the child view that represents the given position in
1652                 * the model.  This is implemented to walk through the children
1653                 * looking for a range that contains the given position.  In this
1654                 * view the children do not necessarily have a one to one mapping 
1655                 * with the child elements.
1656                 *
1657                 * @param pos  the search position >= 0
1658                 * @param a  the allocation to the table on entry, and the
1659                 *   allocation of the view containing the position on exit
1660                 * @return  the view representing the given position, or 
1661                 *   null if there isn't one
1662                 */
1663                protected View getViewAtPosition(int pos, Rectangle a) {
1664                    int n = getViewCount();
1665                    for (int i = 0; i < n; i++) {
1666                        View v = getView(i);
1667                        int p0 = v.getStartOffset();
1668                        int p1 = v.getEndOffset();
1669                        if ((pos >= p0) && (pos < p1)) {
1670                            // it's in this view.
1671                            if (a != null) {
1672                                childAllocation(i, a);
1673                            }
1674                            return v;
1675                        }
1676                    }
1677                    if (pos == getEndOffset()) {
1678                        View v = getView(n - 1);
1679                        if (a != null) {
1680                            this .childAllocation(n - 1, a);
1681                        }
1682                        return v;
1683                    }
1684                    return null;
1685                }
1686
1687                /**
1688                 * Update any cached values that come from attributes.
1689                 */
1690                void setPropertiesFromAttributes() {
1691                    StyleSheet sheet = getStyleSheet();
1692                    attr = sheet.getViewAttributes(this );
1693                    painter = sheet.getBoxPainter(attr);
1694                }
1695
1696                private StyleSheet.BoxPainter painter;
1697                private AttributeSet attr;
1698
1699                /** columns filled by multi-column or multi-row cells */
1700                BitSet fillColumns;
1701
1702                /** 
1703                 * The row index within the overall grid 
1704                 */
1705                int rowIndex;
1706
1707                /**
1708                 * The view index (for row index to view index conversion).
1709                 * This is set by the updateGrid method.
1710                 */
1711                int viewIndex;
1712
1713                /**
1714                 * Does this table row have cells that span multiple rows?
1715                 */
1716                boolean multiRowCells;
1717
1718            }
1719
1720            /**
1721             * Default view of an html table cell.  This needs to be moved
1722             * somewhere else.
1723             */
1724            class CellView extends BlockView {
1725
1726                /**
1727                 * Constructs a TableCell for the given element.
1728                 *
1729                 * @param elem the element that this view is responsible for
1730                 */
1731                public CellView(Element elem) {
1732                    super (elem, Y_AXIS);
1733                }
1734
1735                /**
1736                 * Perform layout for the major axis of the box (i.e. the
1737                 * axis that it represents).  The results of the layout should
1738                 * be placed in the given arrays which represent the allocations
1739                 * to the children along the major axis.  This is called by the
1740                 * superclass to recalculate the positions of the child views
1741                 * when the layout might have changed.
1742                 * <p>
1743                 * This is implemented to delegate to the superclass to
1744                 * tile the children.  If the target span is greater than
1745                 * was needed, the offsets are adjusted to align the children
1746                 * (i.e. position according to the html valign attribute).
1747                 *
1748                 * @param targetSpan the total span given to the view, which
1749                 *  whould be used to layout the children
1750                 * @param axis the axis being layed out
1751                 * @param offsets the offsets from the origin of the view for
1752                 *  each of the child views; this is a return value and is
1753                 *  filled in by the implementation of this method
1754                 * @param spans the span of each child view; this is a return
1755                 *  value and is filled in by the implementation of this method
1756                 * @return the offset and span for each child view in the
1757                 *  offsets and spans parameters
1758                 */
1759                protected void layoutMajorAxis(int targetSpan, int axis,
1760                        int[] offsets, int[] spans) {
1761                    super .layoutMajorAxis(targetSpan, axis, offsets, spans);
1762                    // calculate usage
1763                    int used = 0;
1764                    int n = spans.length;
1765                    for (int i = 0; i < n; i++) {
1766                        used += spans[i];
1767                    }
1768
1769                    // calculate adjustments
1770                    int adjust = 0;
1771                    if (used < targetSpan) {
1772                        // PENDING(prinz) change to use the css alignment.
1773                        String valign = (String) getElement().getAttributes()
1774                                .getAttribute(HTML.Attribute.VALIGN);
1775                        if (valign == null) {
1776                            AttributeSet rowAttr = getElement()
1777                                    .getParentElement().getAttributes();
1778                            valign = (String) rowAttr
1779                                    .getAttribute(HTML.Attribute.VALIGN);
1780                        }
1781                        if ((valign == null) || valign.equals("middle")) {
1782                            adjust = (targetSpan - used) / 2;
1783                        } else if (valign.equals("bottom")) {
1784                            adjust = targetSpan - used;
1785                        }
1786                    }
1787
1788                    // make adjustments.
1789                    if (adjust != 0) {
1790                        for (int i = 0; i < n; i++) {
1791                            offsets[i] += adjust;
1792                        }
1793                    }
1794                }
1795
1796                /**
1797                 * Calculate the requirements needed along the major axis.
1798                 * This is called by the superclass whenever the requirements 
1799                 * need to be updated (i.e. a preferenceChanged was messaged 
1800                 * through this view).  
1801                 * <p>
1802                 * This is implemented to delegate to the superclass, but
1803                 * indicate the maximum size is very large (i.e. the cell 
1804                 * is willing to expend to occupy the full height of the row).
1805                 * 
1806                 * @param axis the axis being layed out.
1807                 * @param r the requirements to fill in.  If null, a new one
1808                 *  should be allocated.
1809                 */
1810                protected SizeRequirements calculateMajorAxisRequirements(
1811                        int axis, SizeRequirements r) {
1812                    SizeRequirements req = super 
1813                            .calculateMajorAxisRequirements(axis, r);
1814                    req.maximum = Integer.MAX_VALUE;
1815                    return req;
1816                }
1817
1818                @Override
1819                protected SizeRequirements calculateMinorAxisRequirements(
1820                        int axis, SizeRequirements r) {
1821                    SizeRequirements rv = super .calculateMinorAxisRequirements(
1822                            axis, r);
1823                    //for the cell the minimum should be derived from the child views 
1824                    //the parent behaviour is to use CSS for that
1825                    int n = getViewCount();
1826                    int min = 0;
1827                    for (int i = 0; i < n; i++) {
1828                        View v = getView(i);
1829                        min = Math.max((int) v.getMinimumSpan(axis), min);
1830                    }
1831                    rv.minimum = Math.min(rv.minimum, min);
1832                    return rv;
1833                }
1834            }
1835
1836        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.