History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/text/html/TableView.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/html/TableView.java+1801−0
@@ -0,0 +1,1801 @@
1+/*
2+ * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package javax.swing.text.html;
26+
27+import java.awt.*;
28+import java.util.BitSet;
29+import java.util.Vector;
30+import java.util.Arrays;
31+import javax.swing.SizeRequirements;
32+import javax.swing.event.DocumentEvent;
33+
34+import javax.swing.text.*;
35+
36+/**
37+ * HTML table view.
38+ *
39+ * @author Timothy Prinzing
40+ * @see View
41+ */
42+/*public*/ class TableView extends BoxView implements ViewFactory {
43+
44+ /**
45+ * Constructs a TableView for the given element.
46+ *
47+ * @param elem the element that this view is responsible for
48+ */
49+ public TableView(Element elem) {
50+ super(elem, View.Y_AXIS);
51+ rows = new Vector<RowView>();
52+ gridValid = false;
53+ captionIndex = -1;
54+ totalColumnRequirements = new SizeRequirements();
55+ }
56+
57+ /**
58+ * Creates a new table row.
59+ *
60+ * @param elem an element
61+ * @return the row
62+ */
63+ protected RowView createTableRow(Element elem) {
64+ // PENDING(prinz) need to add support for some of the other
65+ // elements, but for now just ignore anything that is not
66+ // a TR.
67+ Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
68+ if (o == HTML.Tag.TR) {
69+ return new RowView(elem);
70+ }
71+ return null;
72+ }
73+
74+ /**
75+ * The number of columns in the table.
76+ */
77+ public int getColumnCount() {
78+ return columnSpans.length;
79+ }
80+
81+ /**
82+ * Fetches the span (width) of the given column.
83+ * This is used by the nested cells to query the
84+ * sizes of grid locations outside of themselves.
85+ */
86+ public int getColumnSpan(int col) {
87+ if (col < columnSpans.length) {
88+ return columnSpans[col];
89+ }
90+ return 0;
91+ }
92+
93+ /**
94+ * The number of rows in the table.
95+ */
96+ public int getRowCount() {
97+ return rows.size();
98+ }
99+
100+ /**
101+ * Fetch the span of multiple rows. This includes
102+ * the border area.
103+ */
104+ public int getMultiRowSpan(int row0, int row1) {
105+ RowView rv0 = getRow(row0);
106+ RowView rv1 = getRow(row1);
107+ if ((rv0 != null) && (rv1 != null)) {
108+ int index0 = rv0.viewIndex;
109+ int index1 = rv1.viewIndex;
110+ int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) +
111+ getSpan(Y_AXIS, index1);
112+ return span;
113+ }
114+ return 0;
115+ }
116+
117+ /**
118+ * Fetches the span (height) of the given row.
119+ */
120+ public int getRowSpan(int row) {
121+ RowView rv = getRow(row);
122+ if (rv != null) {
123+ return getSpan(Y_AXIS, rv.viewIndex);
124+ }
125+ return 0;
126+ }
127+
128+ RowView getRow(int row) {
129+ if (row < rows.size()) {
130+ return rows.elementAt(row);
131+ }
132+ return null;
133+ }
134+
135+ protected View getViewAtPoint(int x, int y, Rectangle alloc) {
136+ int n = getViewCount();
137+ View v;
138+ Rectangle allocation = new Rectangle();
139+ for (int i = 0; i < n; i++) {
140+ allocation.setBounds(alloc);
141+ childAllocation(i, allocation);
142+ v = getView(i);
143+ if (v instanceof RowView) {
144+ v = ((RowView)v).findViewAtPoint(x, y, allocation);
145+ if (v != null) {
146+ alloc.setBounds(allocation);
147+ return v;
148+ }
149+ }
150+ }
151+ return super.getViewAtPoint(x, y, alloc);
152+ }
153+
154+ /**
155+ * Determines the number of columns occupied by
156+ * the table cell represented by given element.
157+ */
158+ protected int getColumnsOccupied(View v) {
159+ AttributeSet a = v.getElement().getAttributes();
160+
161+ if (a.isDefined(HTML.Attribute.COLSPAN)) {
162+ String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
163+ if (s != null) {
164+ try {
165+ return Integer.parseInt(s);
166+ } catch (NumberFormatException nfe) {
167+ // fall through to one column
168+ }
169+ }
170+ }
171+
172+ return 1;
173+ }
174+
175+ /**
176+ * Determines the number of rows occupied by
177+ * the table cell represented by given element.
178+ */
179+ protected int getRowsOccupied(View v) {
180+ AttributeSet a = v.getElement().getAttributes();
181+
182+ if (a.isDefined(HTML.Attribute.ROWSPAN)) {
183+ String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
184+ if (s != null) {
185+ try {
186+ return Integer.parseInt(s);
187+ } catch (NumberFormatException nfe) {
188+ // fall through to one row
189+ }
190+ }
191+ }
192+
193+ return 1;
194+ }
195+
196+ protected void invalidateGrid() {
197+ gridValid = false;
198+ }
199+
200+ protected StyleSheet getStyleSheet() {
201+ HTMLDocument doc = (HTMLDocument) getDocument();
202+ return doc.getStyleSheet();
203+ }
204+
205+ /**
206+ * Update the insets, which contain the caption if there
207+ * is a caption.
208+ */
209+ void updateInsets() {
210+ short top = (short) painter.getInset(TOP, this);
211+ short bottom = (short) painter.getInset(BOTTOM, this);
212+ if (captionIndex != -1) {
213+ View caption = getView(captionIndex);
214+ short h = (short) caption.getPreferredSpan(Y_AXIS);
215+ AttributeSet a = caption.getAttributes();
216+ Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);
217+ if ((align != null) && (align.equals("bottom"))) {
218+ bottom += h;
219+ } else {
220+ top += h;
221+ }
222+ }
223+ setInsets(top, (short) painter.getInset(LEFT, this),
224+ bottom, (short) painter.getInset(RIGHT, this));
225+ }
226+
227+ /**
228+ * Update any cached values that come from attributes.
229+ */
230+ protected void setPropertiesFromAttributes() {
231+ StyleSheet sheet = getStyleSheet();
232+ attr = sheet.getViewAttributes(this);
233+ painter = sheet.getBoxPainter(attr);
234+ if (attr != null) {
235+ setInsets((short) painter.getInset(TOP, this),
236+ (short) painter.getInset(LEFT, this),
237+ (short) painter.getInset(BOTTOM, this),
238+ (short) painter.getInset(RIGHT, this));
239+
240+ CSS.LengthValue lv = (CSS.LengthValue)
241+ attr.getAttribute(CSS.Attribute.BORDER_SPACING);
242+ if (lv != null) {
243+ cellSpacing = (int) lv.getValue();
244+ } else {
245+ cellSpacing = 0;
246+ }
247+ lv = (CSS.LengthValue)
248+ attr.getAttribute(CSS.Attribute.BORDER_TOP_WIDTH);
249+ if (lv != null) {
250+ borderWidth = (int) lv.getValue();
251+ } else {
252+ borderWidth = 0;
253+ }
254+
255+ }
256+ }
257+
258+ /**
259+ * Fill in the grid locations that are placeholders
260+ * for multi-column, multi-row, and missing grid
261+ * locations.
262+ */
263+ void updateGrid() {
264+ if (! gridValid) {
265+ relativeCells = false;
266+ multiRowCells = false;
267+
268+ // determine which views are table rows and clear out
269+ // grid points marked filled.
270+ captionIndex = -1;
271+ rows.removeAllElements();
272+ int n = getViewCount();
273+ for (int i = 0; i < n; i++) {
274+ View v = getView(i);
275+ if (v instanceof RowView) {
276+ rows.addElement((RowView) v);
277+ RowView rv = (RowView) v;
278+ rv.clearFilledColumns();
279+ rv.rowIndex = rows.size() - 1;
280+ rv.viewIndex = i;
281+ } else {
282+ Object o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute);
283+ if (o instanceof HTML.Tag) {
284+ HTML.Tag kind = (HTML.Tag) o;
285+ if (kind == HTML.Tag.CAPTION) {
286+ captionIndex = i;
287+ }
288+ }
289+ }
290+ }
291+
292+ int maxColumns = 0;
293+ int nrows = rows.size();
294+ for (int row = 0; row < nrows; row++) {
295+ RowView rv = getRow(row);
296+ int col = 0;
297+ for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
298+ View cv = rv.getView(cell);
299+ if (! relativeCells) {
300+ AttributeSet a = cv.getAttributes();
301+ CSS.LengthValue lv = (CSS.LengthValue)
302+ a.getAttribute(CSS.Attribute.WIDTH);
303+ if ((lv != null) && (lv.isPercentage())) {
304+ relativeCells = true;
305+ }
306+ }
307+ // advance to a free column
308+ for (; rv.isFilled(col); col++);
309+ int rowSpan = getRowsOccupied(cv);
310+ if (rowSpan > 1) {
311+ multiRowCells = true;
312+ }
313+ int colSpan = getColumnsOccupied(cv);
314+ if ((colSpan > 1) || (rowSpan > 1)) {
315+ // fill in the overflow entries for this cell
316+ int rowLimit = row + rowSpan;
317+ int colLimit = col + colSpan;
318+ for (int i = row; i < rowLimit; i++) {
319+ for (int j = col; j < colLimit; j++) {
320+ if (i != row || j != col) {
321+ addFill(i, j);
322+ }
323+ }
324+ }
325+ if (colSpan > 1) {
326+ col += colSpan - 1;
327+ }
328+ }
329+ }
330+ maxColumns = Math.max(maxColumns, col);
331+ }
332+
333+ // setup the column layout/requirements
334+ columnSpans = new int[maxColumns];
335+ columnOffsets = new int[maxColumns];
336+ columnRequirements = new SizeRequirements[maxColumns];
337+ for (int i = 0; i < maxColumns; i++) {
338+ columnRequirements[i] = new SizeRequirements();
339+ columnRequirements[i].maximum = Integer.MAX_VALUE;
340+ }
341+ gridValid = true;
342+ }
343+ }
344+
345+ /**
346+ * Mark a grid location as filled in for a cells overflow.
347+ */
348+ void addFill(int row, int col) {
349+ RowView rv = getRow(row);
350+ if (rv != null) {
351+ rv.fillColumn(col);
352+ }
353+ }
354+
355+ /**
356+ * Layout the columns to fit within the given target span.
357+ *
358+ * @param targetSpan the given span for total of all the table
359+ * columns
360+ * @param reqs the requirements desired for each column. This
361+ * is the column maximum of the cells minimum, preferred, and
362+ * maximum requested span
363+ * @param spans the return value of how much to allocated to
364+ * each column
365+ * @param offsets the return value of the offset from the
366+ * origin for each column
367+ * @return the offset from the origin and the span for each column
368+ * in the offsets and spans parameters
369+ */
370+ protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
371+ SizeRequirements[] reqs) {
372+ //clean offsets and spans
373+ Arrays.fill(offsets, 0);
374+ Arrays.fill(spans, 0);
375+ colIterator.setLayoutArrays(offsets, spans, targetSpan);
376+ CSS.calculateTiledLayout(colIterator, targetSpan);
377+ }
378+
379+ /**
380+ * Calculate the requirements for each column. The calculation
381+ * is done as two passes over the table. The table cells that
382+ * occupy a single column are scanned first to determine the
383+ * maximum of minimum, preferred, and maximum spans along the
384+ * give axis. Table cells that span multiple columns are excluded
385+ * from the first pass. A second pass is made to determine if
386+ * the cells that span multiple columns are satisfied. If the
387+ * column requirements are not satisified, the needs of the
388+ * multi-column cell is mixed into the existing column requirements.
389+ * The calculation of the multi-column distribution is based upon
390+ * the proportions of the existing column requirements and taking
391+ * into consideration any constraining maximums.
392+ */
393+ void calculateColumnRequirements(int axis) {
394+ // clean columnRequirements
395+ for (SizeRequirements req : columnRequirements) {
396+ req.minimum = 0;
397+ req.preferred = 0;
398+ req.maximum = Integer.MAX_VALUE;
399+ }
400+ Container host = getContainer();
401+ if (host != null) {
402+ if (host instanceof JTextComponent) {
403+ skipComments = !((JTextComponent)host).isEditable();
404+ } else {
405+ skipComments = true;
406+ }
407+ }
408+ // pass 1 - single column cells
409+ boolean hasMultiColumn = false;
410+ int nrows = getRowCount();
411+ for (int i = 0; i < nrows; i++) {
412+ RowView row = getRow(i);
413+ int col = 0;
414+ int ncells = row.getViewCount();
415+ for (int cell = 0; cell < ncells; cell++) {
416+ View cv = row.getView(cell);
417+ if (skipComments && !(cv instanceof CellView)) {
418+ continue;
419+ }
420+ for (; row.isFilled(col); col++); // advance to a free column
421+ int rowSpan = getRowsOccupied(cv);
422+ int colSpan = getColumnsOccupied(cv);
423+ if (colSpan == 1) {
424+ checkSingleColumnCell(axis, col, cv);
425+ } else {
426+ hasMultiColumn = true;
427+ col += colSpan - 1;
428+ }
429+ col++;
430+ }
431+ }
432+
433+ // pass 2 - multi-column cells
434+ if (hasMultiColumn) {
435+ for (int i = 0; i < nrows; i++) {
436+ RowView row = getRow(i);
437+ int col = 0;
438+ int ncells = row.getViewCount();
439+ for (int cell = 0; cell < ncells; cell++) {
440+ View cv = row.getView(cell);
441+ if (skipComments && !(cv instanceof CellView)) {
442+ continue;
443+ }
444+ for (; row.isFilled(col); col++); // advance to a free column
445+ int colSpan = getColumnsOccupied(cv);
446+ if (colSpan > 1) {
447+ checkMultiColumnCell(axis, col, colSpan, cv);
448+ col += colSpan - 1;
449+ }
450+ col++;
451+ }
452+ }
453+ }
454+ }
455+
456+ /**
457+ * check the requirements of a table cell that spans a single column.
458+ */
459+ void checkSingleColumnCell(int axis, int col, View v) {
460+ SizeRequirements req = columnRequirements[col];
461+ req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
462+ req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
463+ }
464+
465+ /**
466+ * check the requirements of a table cell that spans multiple
467+ * columns.
468+ */
469+ void checkMultiColumnCell(int axis, int col, int ncols, View v) {
470+ // calculate the totals
471+ long min = 0;
472+ long pref = 0;
473+ long max = 0;
474+ for (int i = 0; i < ncols; i++) {
475+ SizeRequirements req = columnRequirements[col + i];
476+ min += req.minimum;
477+ pref += req.preferred;
478+ max += req.maximum;
479+ }
480+
481+ // check if the minimum size needs adjustment.
482+ int cmin = (int) v.getMinimumSpan(axis);
483+ if (cmin > min) {
484+ /*
485+ * the columns that this cell spans need adjustment to fit
486+ * this table cell.... calculate the adjustments.
487+ */
488+ SizeRequirements[] reqs = new SizeRequirements[ncols];
489+ for (int i = 0; i < ncols; i++) {
490+ reqs[i] = columnRequirements[col + i];
491+ }
492+ int[] spans = new int[ncols];
493+ int[] offsets = new int[ncols];
494+ SizeRequirements.calculateTiledPositions(cmin, null, reqs,
495+ offsets, spans);
496+ // apply the adjustments
497+ for (int i = 0; i < ncols; i++) {
498+ SizeRequirements req = reqs[i];
499+ req.minimum = Math.max(spans[i], req.minimum);
500+ req.preferred = Math.max(req.minimum, req.preferred);
501+ req.maximum = Math.max(req.preferred, req.maximum);
502+ }
503+ }
504+
505+ // check if the preferred size needs adjustment.
506+ int cpref = (int) v.getPreferredSpan(axis);
507+ if (cpref > pref) {
508+ /*
509+ * the columns that this cell spans need adjustment to fit
510+ * this table cell.... calculate the adjustments.
511+ */
512+ SizeRequirements[] reqs = new SizeRequirements[ncols];
513+ for (int i = 0; i < ncols; i++) {
514+ reqs[i] = columnRequirements[col + i];
515+ }
516+ int[] spans = new int[ncols];
517+ int[] offsets = new int[ncols];
518+ SizeRequirements.calculateTiledPositions(cpref, null, reqs,
519+ offsets, spans);
520+ // apply the adjustments
521+ for (int i = 0; i < ncols; i++) {
522+ SizeRequirements req = reqs[i];
523+ req.preferred = Math.max(spans[i], req.preferred);
524+ req.maximum = Math.max(req.preferred, req.maximum);
525+ }
526+ }
527+
528+ }
529+
530+ // --- BoxView methods -----------------------------------------
531+
532+ /**
533+ * Calculate the requirements for the minor axis. This is called by
534+ * the superclass whenever the requirements need to be updated (i.e.
535+ * a preferenceChanged was messaged through this view).
536+ * <p>
537+ * This is implemented to calculate the requirements as the sum of the
538+ * requirements of the columns and then adjust it if the
539+ * CSS width or height attribute is specified and applicable to
540+ * the axis.
541+ */
542+ protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
543+ updateGrid();
544+
545+ // calculate column requirements for each column
546+ calculateColumnRequirements(axis);
547+
548+
549+ // the requirements are the sum of the columns.
550+ if (r == null) {
551+ r = new SizeRequirements();
552+ }
553+ long min = 0;
554+ long pref = 0;
555+ int n = columnRequirements.length;
556+ for (int i = 0; i < n; i++) {
557+ SizeRequirements req = columnRequirements[i];
558+ min += req.minimum;
559+ pref += req.preferred;
560+ }
561+ int adjust = (n + 1) * cellSpacing + 2 * borderWidth;
562+ min += adjust;
563+ pref += adjust;
564+ r.minimum = (int) min;
565+ r.preferred = (int) pref;
566+ r.maximum = (int) pref;
567+
568+
569+ AttributeSet attr = getAttributes();
570+ CSS.LengthValue cssWidth = (CSS.LengthValue)attr.getAttribute(
571+ CSS.Attribute.WIDTH);
572+
573+ if (BlockView.spanSetFromAttributes(axis, r, cssWidth, null)) {
574+ if (r.minimum < (int)min) {
575+ // The user has requested a smaller size than is needed to
576+ // show the table, override it.
577+ r.maximum = r.minimum = r.preferred = (int) min;
578+ }
579+ }
580+ totalColumnRequirements.minimum = r.minimum;
581+ totalColumnRequirements.preferred = r.preferred;
582+ totalColumnRequirements.maximum = r.maximum;
583+
584+ // set the alignment
585+ Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
586+ if (o != null) {
587+ // set horizontal alignment
588+ String ta = o.toString();
589+ if (ta.equals("left")) {
590+ r.alignment = 0;
591+ } else if (ta.equals("center")) {
592+ r.alignment = 0.5f;
593+ } else if (ta.equals("right")) {
594+ r.alignment = 1;
595+ } else {
596+ r.alignment = 0;
597+ }
598+ } else {
599+ r.alignment = 0;
600+ }
601+
602+ return r;
603+ }
604+
605+ /**
606+ * Calculate the requirements for the major axis. This is called by
607+ * the superclass whenever the requirements need to be updated (i.e.
608+ * a preferenceChanged was messaged through this view).
609+ * <p>
610+ * This is implemented to provide the superclass behavior adjusted for
611+ * multi-row table cells.
612+ */
613+ protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
614+ updateInsets();
615+ rowIterator.updateAdjustments();
616+ r = CSS.calculateTiledRequirements(rowIterator, r);
617+ r.maximum = r.preferred;
618+ return r;
619+ }
620+
621+ /**
622+ * Perform layout for the minor axis of the box (i.e. the
623+ * axis orthoginal to the axis that it represents). The results
624+ * of the layout should be placed in the given arrays which represent
625+ * the allocations to the children along the minor axis. This
626+ * is called by the superclass whenever the layout needs to be
627+ * updated along the minor axis.
628+ * <p>
629+ * This is implemented to call the
630+ * <a href="#layoutColumns">layoutColumns</a> method, and then
631+ * forward to the superclass to actually carry out the layout
632+ * of the tables rows.
633+ *
634+ * @param targetSpan the total span given to the view, which
635+ * whould be used to layout the children
636+ * @param axis the axis being layed out
637+ * @param offsets the offsets from the origin of the view for
638+ * each of the child views. This is a return value and is
639+ * filled in by the implementation of this method
640+ * @param spans the span of each child view; this is a return
641+ * value and is filled in by the implementation of this method
642+ * @return the offset and span for each child view in the
643+ * offsets and spans parameters
644+ */
645+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
646+ // make grid is properly represented
647+ updateGrid();
648+
649+ // all of the row layouts are invalid, so mark them that way
650+ int n = getRowCount();
651+ for (int i = 0; i < n; i++) {
652+ RowView row = getRow(i);
653+ row.layoutChanged(axis);
654+ }
655+
656+ // calculate column spans
657+ layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
658+
659+ // continue normal layout
660+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
661+ }
662+
663+
664+ /**
665+ * Perform layout for the major axis of the box (i.e. the
666+ * axis that it represents). The results
667+ * of the layout should be placed in the given arrays which represent
668+ * the allocations to the children along the minor axis. This
669+ * is called by the superclass whenever the layout needs to be
670+ * updated along the minor axis.
671+ * <p>
672+ * This method is where the layout of the table rows within the
673+ * table takes place. This method is implemented to call the use
674+ * the RowIterator and the CSS collapsing tile to layout
675+ * with border spacing and border collapsing capabilities.
676+ *
677+ * @param targetSpan the total span given to the view, which
678+ * whould be used to layout the children
679+ * @param axis the axis being layed out
680+ * @param offsets the offsets from the origin of the view for
681+ * each of the child views; this is a return value and is
682+ * filled in by the implementation of this method
683+ * @param spans the span of each child view; this is a return
684+ * value and is filled in by the implementation of this method
685+ * @return the offset and span for each child view in the
686+ * offsets and spans parameters
687+ */
688+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
689+ rowIterator.setLayoutArrays(offsets, spans);
690+ CSS.calculateTiledLayout(rowIterator, targetSpan);
691+
692+ if (captionIndex != -1) {
693+ // place the caption
694+ View caption = getView(captionIndex);
695+ int h = (int) caption.getPreferredSpan(Y_AXIS);
696+ spans[captionIndex] = h;
697+ short boxBottom = (short) painter.getInset(BOTTOM, this);
698+ if (boxBottom != getBottomInset()) {
699+ offsets[captionIndex] = targetSpan + boxBottom;
700+ } else {
701+ offsets[captionIndex] = - getTopInset();
702+ }
703+ }
704+ }
705+
706+ /**
707+ * Fetches the child view that represents the given position in
708+ * the model. This is implemented to walk through the children
709+ * looking for a range that contains the given position. In this
710+ * view the children do not necessarily have a one to one mapping
711+ * with the child elements.
712+ *
713+ * @param pos the search position >= 0
714+ * @param a the allocation to the table on entry, and the
715+ * allocation of the view containing the position on exit
716+ * @return the view representing the given position, or
717+ * null if there isn't one
718+ */
719+ protected View getViewAtPosition(int pos, Rectangle a) {
720+ int n = getViewCount();
721+ for (int i = 0; i < n; i++) {
722+ View v = getView(i);
723+ int p0 = v.getStartOffset();
724+ int p1 = v.getEndOffset();
725+ if ((pos >= p0) && (pos < p1)) {
726+ // it's in this view.
727+ if (a != null) {
728+ childAllocation(i, a);
729+ }
730+ return v;
731+ }
732+ }
733+ if (pos == getEndOffset()) {
734+ View v = getView(n - 1);
735+ if (a != null) {
736+ this.childAllocation(n - 1, a);
737+ }
738+ return v;
739+ }
740+ return null;
741+ }
742+
743+ // --- View methods ---------------------------------------------
744+
745+ /**
746+ * Fetches the attributes to use when rendering. This is
747+ * implemented to multiplex the attributes specified in the
748+ * model with a StyleSheet.
749+ */
750+ public AttributeSet getAttributes() {
751+ if (attr == null) {
752+ StyleSheet sheet = getStyleSheet();
753+ attr = sheet.getViewAttributes(this);
754+ }
755+ return attr;
756+ }
757+
758+ /**
759+ * Renders using the given rendering surface and area on that
760+ * surface. This is implemented to delegate to the css box
761+ * painter to paint the border and background prior to the
762+ * interior. The superclass culls rendering the children
763+ * that don't directly intersect the clip and the row may
764+ * have cells hanging from a row above in it. The table
765+ * does not use the superclass rendering behavior and instead
766+ * paints all of the rows and lets the rows cull those
767+ * cells not intersecting the clip region.
768+ *
769+ * @param g the rendering surface to use
770+ * @param allocation the allocated region to render into
771+ * @see View#paint
772+ */
773+ public void paint(Graphics g, Shape allocation) {
774+ // paint the border
775+ Rectangle a = allocation.getBounds();
776+ setSize(a.width, a.height);
777+ if (captionIndex != -1) {
778+ // adjust the border for the caption
779+ short top = (short) painter.getInset(TOP, this);
780+ short bottom = (short) painter.getInset(BOTTOM, this);
781+ if (top != getTopInset()) {
782+ int h = getTopInset() - top;
783+ a.y += h;
784+ a.height -= h;
785+ } else {
786+ a.height -= getBottomInset() - bottom;
787+ }
788+ }
789+ painter.paint(g, a.x, a.y, a.width, a.height, this);
790+ // paint interior
791+ int n = getViewCount();
792+ for (int i = 0; i < n; i++) {
793+ View v = getView(i);
794+ v.paint(g, getChildAllocation(i, allocation));
795+ }
796+ //super.paint(g, a);
797+ }
798+
799+ /**
800+ * Establishes the parent view for this view. This is
801+ * guaranteed to be called before any other methods if the
802+ * parent view is functioning properly.
803+ * <p>
804+ * This is implemented
805+ * to forward to the superclass as well as call the
806+ * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
807+ * method to set the paragraph properties from the css
808+ * attributes. The call is made at this time to ensure
809+ * the ability to resolve upward through the parents
810+ * view attributes.
811+ *
812+ * @param parent the new parent, or null if the view is
813+ * being removed from a parent it was previously added
814+ * to
815+ */
816+ public void setParent(View parent) {
817+ super.setParent(parent);
818+ if (parent != null) {
819+ setPropertiesFromAttributes();
820+ }
821+ }
822+
823+ /**
824+ * Fetches the ViewFactory implementation that is feeding
825+ * the view hierarchy.
826+ * This replaces the ViewFactory with an implementation that
827+ * calls through to the createTableRow and createTableCell
828+ * methods. If the element given to the factory isn't a
829+ * table row or cell, the request is delegated to the factory
830+ * produced by the superclass behavior.
831+ *
832+ * @return the factory, null if none
833+ */
834+ public ViewFactory getViewFactory() {
835+ return this;
836+ }
837+
838+ /**
839+ * Gives notification that something was inserted into
840+ * the document in a location that this view is responsible for.
841+ * This replaces the ViewFactory with an implementation that
842+ * calls through to the createTableRow and createTableCell
843+ * methods. If the element given to the factory isn't a
844+ * table row or cell, the request is delegated to the factory
845+ * passed as an argument.
846+ *
847+ * @param e the change information from the associated document
848+ * @param a the current allocation of the view
849+ * @param f the factory to use to rebuild if the view has children
850+ * @see View#insertUpdate
851+ */
852+ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
853+ super.insertUpdate(e, a, this);
854+ }
855+
856+ /**
857+ * Gives notification that something was removed from the document
858+ * in a location that this view is responsible for.
859+ * This replaces the ViewFactory with an implementation that
860+ * calls through to the createTableRow and createTableCell
861+ * methods. If the element given to the factory isn't a
862+ * table row or cell, the request is delegated to the factory
863+ * passed as an argument.
864+ *
865+ * @param e the change information from the associated document
866+ * @param a the current allocation of the view
867+ * @param f the factory to use to rebuild if the view has children
868+ * @see View#removeUpdate
869+ */
870+ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
871+ super.removeUpdate(e, a, this);
872+ }
873+
874+ /**
875+ * Gives notification from the document that attributes were changed
876+ * in a location that this view is responsible for.
877+ * This replaces the ViewFactory with an implementation that
878+ * calls through to the createTableRow and createTableCell
879+ * methods. If the element given to the factory isn't a
880+ * table row or cell, the request is delegated to the factory
881+ * passed as an argument.
882+ *
883+ * @param e the change information from the associated document
884+ * @param a the current allocation of the view
885+ * @param f the factory to use to rebuild if the view has children
886+ * @see View#changedUpdate
887+ */
888+ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
889+ super.changedUpdate(e, a, this);
890+ }
891+
892+ protected void forwardUpdate(DocumentEvent.ElementChange ec,
893+ DocumentEvent e, Shape a, ViewFactory f) {
894+ super.forwardUpdate(ec, e, a, f);
895+ // A change in any of the table cells usually effects the whole table,
896+ // so redraw it all!
897+ if (a != null) {
898+ Component c = getContainer();
899+ if (c != null) {
900+ Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
901+ a.getBounds();
902+ c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
903+ }
904+ }
905+ }
906+
907+ /**
908+ * Change the child views. This is implemented to
909+ * provide the superclass behavior and invalidate the
910+ * grid so that rows and columns will be recalculated.
911+ */
912+ public void replace(int offset, int length, View[] views) {
913+ super.replace(offset, length, views);
914+ invalidateGrid();
915+ }
916+
917+ // --- ViewFactory methods ------------------------------------------
918+
919+ /**
920+ * The table itself acts as a factory for the various
921+ * views that actually represent pieces of the table.
922+ * All other factory activity is delegated to the factory
923+ * returned by the parent of the table.
924+ */
925+ public View create(Element elem) {
926+ Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
927+ if (o instanceof HTML.Tag) {
928+ HTML.Tag kind = (HTML.Tag) o;
929+ if (kind == HTML.Tag.TR) {
930+ return createTableRow(elem);
931+ } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
932+ return new CellView(elem);
933+ } else if (kind == HTML.Tag.CAPTION) {
934+ return new javax.swing.text.html.ParagraphView(elem);
935+ }
936+ }
937+ // default is to delegate to the normal factory
938+ View p = getParent();
939+ if (p != null) {
940+ ViewFactory f = p.getViewFactory();
941+ if (f != null) {
942+ return f.create(elem);
943+ }
944+ }
945+ return null;
946+ }
947+
948+ // ---- variables ----------------------------------------------------
949+
950+ private AttributeSet attr;
951+ private StyleSheet.BoxPainter painter;
952+
953+ private int cellSpacing;
954+ private int borderWidth;
955+
956+ /**
957+ * The index of the caption view if there is a caption.
958+ * This has a value of -1 if there is no caption. The
959+ * caption lives in the inset area of the table, and is
960+ * updated with each time the grid is recalculated.
961+ */
962+ private int captionIndex;
963+
964+ /**
965+ * Do any of the table cells contain a relative size
966+ * specification? This is updated with each call to
967+ * updateGrid(). If this is true, the ColumnIterator
968+ * will do extra work to calculate relative cell
969+ * specifications.
970+ */
971+ private boolean relativeCells;
972+
973+ /**
974+ * Do any of the table cells span multiple rows? If
975+ * true, the RowRequirementIterator will do additional
976+ * work to adjust the requirements of rows spanned by
977+ * a single table cell. This is updated with each call to
978+ * updateGrid().
979+ */
980+ private boolean multiRowCells;
981+
982+ int[] columnSpans;
983+ int[] columnOffsets;
984+ /**
985+ * SizeRequirements for all the columns.
986+ */
987+ SizeRequirements totalColumnRequirements;
988+ SizeRequirements[] columnRequirements;
989+
990+ RowIterator rowIterator = new RowIterator();
991+ ColumnIterator colIterator = new ColumnIterator();
992+
993+ Vector<RowView> rows;
994+
995+ // whether to display comments inside table or not.
996+ boolean skipComments = false;
997+
998+ boolean gridValid;
999+ static final private BitSet EMPTY = new BitSet();
1000+
1001+ class ColumnIterator implements CSS.LayoutIterator {
1002+
1003+ /**
1004+ * Disable percentage adjustments which should only apply
1005+ * when calculating layout, not requirements.
1006+ */
1007+ void disablePercentages() {
1008+ percentages = null;
1009+ }
1010+
1011+ /**
1012+ * Update percentage adjustments if they are needed.
1013+ */
1014+ private void updatePercentagesAndAdjustmentWeights(int span) {
1015+ adjustmentWeights = new int[columnRequirements.length];
1016+ for (int i = 0; i < columnRequirements.length; i++) {
1017+ adjustmentWeights[i] = 0;
1018+ }
1019+ if (relativeCells) {
1020+ percentages = new int[columnRequirements.length];
1021+ } else {
1022+ percentages = null;
1023+ }
1024+ int nrows = getRowCount();
1025+ for (int rowIndex = 0; rowIndex < nrows; rowIndex++) {
1026+ RowView row = getRow(rowIndex);
1027+ int col = 0;
1028+ int ncells = row.getViewCount();
1029+ for (int cell = 0; cell < ncells; cell++, col++) {
1030+ View cv = row.getView(cell);
1031+ for (; row.isFilled(col); col++); // advance to a free column
1032+ int rowSpan = getRowsOccupied(cv);
1033+ int colSpan = getColumnsOccupied(cv);
1034+ AttributeSet a = cv.getAttributes();
1035+ CSS.LengthValue lv = (CSS.LengthValue)
1036+ a.getAttribute(CSS.Attribute.WIDTH);
1037+ if ( lv != null ) {
1038+ int len = (int) (lv.getValue(span) / colSpan + 0.5f);
1039+ for (int i = 0; i < colSpan; i++) {
1040+ if (lv.isPercentage()) {
1041+ // add a percentage requirement
1042+ percentages[col+i] = Math.max(percentages[col+i], len);
1043+ adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight);
1044+ } else {
1045+ adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight - 1);
1046+ }
1047+ }
1048+ }
1049+ col += colSpan - 1;
1050+ }
1051+ }
1052+ }
1053+
1054+ /**
1055+ * Set the layout arrays to use for holding layout results
1056+ */
1057+ public void setLayoutArrays(int offsets[], int spans[], int targetSpan) {
1058+ this.offsets = offsets;
1059+ this.spans = spans;
1060+ updatePercentagesAndAdjustmentWeights(targetSpan);
1061+ }
1062+
1063+ // --- RequirementIterator methods -------------------
1064+
1065+ public int getCount() {
1066+ return columnRequirements.length;
1067+ }
1068+
1069+ public void setIndex(int i) {
1070+ col = i;
1071+ }
1072+
1073+ public void setOffset(int offs) {
1074+ offsets[col] = offs;
1075+ }
1076+
1077+ public int getOffset() {
1078+ return offsets[col];
1079+ }
1080+
1081+ public void setSpan(int span) {
1082+ spans[col] = span;
1083+ }
1084+
1085+ public int getSpan() {
1086+ return spans[col];
1087+ }
1088+
1089+ public float getMinimumSpan(float parentSpan) {
1090+ // do not care for percentages, since min span can't
1091+ // be less than columnRequirements[col].minimum,
1092+ // but can be less than percentage value.
1093+ return columnRequirements[col].minimum;
1094+ }
1095+
1096+ public float getPreferredSpan(float parentSpan) {
1097+ if ((percentages != null) && (percentages[col] != 0)) {
1098+ return Math.max(percentages[col], columnRequirements[col].minimum);
1099+ }
1100+ return columnRequirements[col].preferred;
1101+ }
1102+
1103+ public float getMaximumSpan(float parentSpan) {
1104+ return columnRequirements[col].maximum;
1105+ }
1106+
1107+ public float getBorderWidth() {
1108+ return borderWidth;
1109+ }
1110+
1111+
1112+ public float getLeadingCollapseSpan() {
1113+ return cellSpacing;
1114+ }
1115+
1116+ public float getTrailingCollapseSpan() {
1117+ return cellSpacing;
1118+ }
1119+
1120+ public int getAdjustmentWeight() {
1121+ return adjustmentWeights[col];
1122+ }
1123+
1124+ /**
1125+ * Current column index
1126+ */
1127+ private int col;
1128+
1129+ /**
1130+ * percentage values (may be null since there
1131+ * might not be any).
1132+ */
1133+ private int[] percentages;
1134+
1135+ private int[] adjustmentWeights;
1136+
1137+ private int[] offsets;
1138+ private int[] spans;
1139+ }
1140+
1141+ class RowIterator implements CSS.LayoutIterator {
1142+
1143+ RowIterator() {
1144+ }
1145+
1146+ void updateAdjustments() {
1147+ int axis = Y_AXIS;
1148+ if (multiRowCells) {
1149+ // adjust requirements of multi-row cells
1150+ int n = getRowCount();
1151+ adjustments = new int[n];
1152+ for (int i = 0; i < n; i++) {
1153+ RowView rv = getRow(i);
1154+ if (rv.multiRowCells == true) {
1155+ int ncells = rv.getViewCount();
1156+ for (int j = 0; j < ncells; j++) {
1157+ View v = rv.getView(j);
1158+ int nrows = getRowsOccupied(v);
1159+ if (nrows > 1) {
1160+ int spanNeeded = (int) v.getPreferredSpan(axis);
1161+ adjustMultiRowSpan(spanNeeded, nrows, i);
1162+ }
1163+ }
1164+ }
1165+ }
1166+ } else {
1167+ adjustments = null;
1168+ }
1169+ }
1170+
1171+ /**
1172+ * Fixup preferences to accomodate a multi-row table cell
1173+ * if not already covered by existing preferences. This is
1174+ * a no-op if not all of the rows needed (to do this check/fixup)
1175+ * have arrived yet.
1176+ */
1177+ void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) {
1178+ if ((rowIndex + nrows) > getCount()) {
1179+ // rows are missing (could be a bad rowspan specification)
1180+ // or not all the rows have arrived. Do the best we can with
1181+ // the current set of rows.
1182+ nrows = getCount() - rowIndex;
1183+ if (nrows < 1) {
1184+ return;
1185+ }
1186+ }
1187+ int span = 0;
1188+ for (int i = 0; i < nrows; i++) {
1189+ RowView rv = getRow(rowIndex + i);
1190+ span += rv.getPreferredSpan(Y_AXIS);
1191+ }
1192+ if (spanNeeded > span) {
1193+ int adjust = (spanNeeded - span);
1194+ int rowAdjust = adjust / nrows;
1195+ int firstAdjust = rowAdjust + (adjust - (rowAdjust * nrows));
1196+ RowView rv = getRow(rowIndex);
1197+ adjustments[rowIndex] = Math.max(adjustments[rowIndex],
1198+ firstAdjust);
1199+ for (int i = 1; i < nrows; i++) {
1200+ adjustments[rowIndex + i] = Math.max(
1201+ adjustments[rowIndex + i], rowAdjust);
1202+ }
1203+ }
1204+ }
1205+
1206+ void setLayoutArrays(int[] offsets, int[] spans) {
1207+ this.offsets = offsets;
1208+ this.spans = spans;
1209+ }
1210+
1211+ // --- RequirementIterator methods -------------------
1212+
1213+ public void setOffset(int offs) {
1214+ RowView rv = getRow(row);
1215+ if (rv != null) {
1216+ offsets[rv.viewIndex] = offs;
1217+ }
1218+ }
1219+
1220+ public int getOffset() {
1221+ RowView rv = getRow(row);
1222+ if (rv != null) {
1223+ return offsets[rv.viewIndex];
1224+ }
1225+ return 0;
1226+ }
1227+
1228+ public void setSpan(int span) {
1229+ RowView rv = getRow(row);
1230+ if (rv != null) {
1231+ spans[rv.viewIndex] = span;
1232+ }
1233+ }
1234+
1235+ public int getSpan() {
1236+ RowView rv = getRow(row);
1237+ if (rv != null) {
1238+ return spans[rv.viewIndex];
1239+ }
1240+ return 0;
1241+ }
1242+
1243+ public int getCount() {
1244+ return rows.size();
1245+ }
1246+
1247+ public void setIndex(int i) {
1248+ row = i;
1249+ }
1250+
1251+ public float getMinimumSpan(float parentSpan) {
1252+ return getPreferredSpan(parentSpan);
1253+ }
1254+
1255+ public float getPreferredSpan(float parentSpan) {
1256+ RowView rv = getRow(row);
1257+ if (rv != null) {
1258+ int adjust = (adjustments != null) ? adjustments[row] : 0;
1259+ return rv.getPreferredSpan(TableView.this.getAxis()) + adjust;
1260+ }
1261+ return 0;
1262+ }
1263+
1264+ public float getMaximumSpan(float parentSpan) {
1265+ return getPreferredSpan(parentSpan);
1266+ }
1267+
1268+ public float getBorderWidth() {
1269+ return borderWidth;
1270+ }
1271+
1272+ public float getLeadingCollapseSpan() {
1273+ return cellSpacing;
1274+ }
1275+
1276+ public float getTrailingCollapseSpan() {
1277+ return cellSpacing;
1278+ }
1279+
1280+ public int getAdjustmentWeight() {
1281+ return 0;
1282+ }
1283+
1284+ /**
1285+ * Current row index
1286+ */
1287+ private int row;
1288+
1289+ /**
1290+ * Adjustments to the row requirements to handle multi-row
1291+ * table cells.
1292+ */
1293+ private int[] adjustments;
1294+
1295+ private int[] offsets;
1296+ private int[] spans;
1297+ }
1298+
1299+ /**
1300+ * View of a row in a row-centric table.
1301+ */
1302+ public class RowView extends BoxView {
1303+
1304+ /**
1305+ * Constructs a TableView for the given element.
1306+ *
1307+ * @param elem the element that this view is responsible for
1308+ */
1309+ public RowView(Element elem) {
1310+ super(elem, View.X_AXIS);
1311+ fillColumns = new BitSet();
1312+ RowView.this.setPropertiesFromAttributes();
1313+ }
1314+
1315+ void clearFilledColumns() {
1316+ fillColumns.and(EMPTY);
1317+ }
1318+
1319+ void fillColumn(int col) {
1320+ fillColumns.set(col);
1321+ }
1322+
1323+ boolean isFilled(int col) {
1324+ return fillColumns.get(col);
1325+ }
1326+
1327+ /**
1328+ * The number of columns present in this row.
1329+ */
1330+ int getColumnCount() {
1331+ int nfill = 0;
1332+ int n = fillColumns.size();
1333+ for (int i = 0; i < n; i++) {
1334+ if (fillColumns.get(i)) {
1335+ nfill ++;
1336+ }
1337+ }
1338+ return getViewCount() + nfill;
1339+ }
1340+
1341+ /**
1342+ * Fetches the attributes to use when rendering. This is
1343+ * implemented to multiplex the attributes specified in the
1344+ * model with a StyleSheet.
1345+ */
1346+ public AttributeSet getAttributes() {
1347+ return attr;
1348+ }
1349+
1350+ View findViewAtPoint(int x, int y, Rectangle alloc) {
1351+ int n = getViewCount();
1352+ for (int i = 0; i < n; i++) {
1353+ if (getChildAllocation(i, alloc).contains(x, y)) {
1354+ childAllocation(i, alloc);
1355+ return getView(i);
1356+ }
1357+ }
1358+ return null;
1359+ }
1360+
1361+ protected StyleSheet getStyleSheet() {
1362+ HTMLDocument doc = (HTMLDocument) getDocument();
1363+ return doc.getStyleSheet();
1364+ }
1365+
1366+ /**
1367+ * This is called by a child to indicate its
1368+ * preferred span has changed. This is implemented to
1369+ * execute the superclass behavior and well as try to
1370+ * determine if a row with a multi-row cell hangs across
1371+ * this row. If a multi-row cell covers this row it also
1372+ * needs to propagate a preferenceChanged so that it will
1373+ * recalculate the multi-row cell.
1374+ *
1375+ * @param child the child view
1376+ * @param width true if the width preference should change
1377+ * @param height true if the height preference should change
1378+ */
1379+ public void preferenceChanged(View child, boolean width, boolean height) {
1380+ super.preferenceChanged(child, width, height);
1381+ if (TableView.this.multiRowCells && height) {
1382+ for (int i = rowIndex - 1; i >= 0; i--) {
1383+ RowView rv = TableView.this.getRow(i);
1384+ if (rv.multiRowCells) {
1385+ rv.preferenceChanged(null, false, true);
1386+ break;
1387+ }
1388+ }
1389+ }
1390+ }
1391+
1392+ // The major axis requirements for a row are dictated by the column
1393+ // requirements. These methods use the value calculated by
1394+ // TableView.
1395+ protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
1396+ SizeRequirements req = new SizeRequirements();
1397+ req.minimum = totalColumnRequirements.minimum;
1398+ req.maximum = totalColumnRequirements.maximum;
1399+ req.preferred = totalColumnRequirements.preferred;
1400+ req.alignment = 0f;
1401+ return req;
1402+ }
1403+
1404+ public float getMinimumSpan(int axis) {
1405+ float value;
1406+
1407+ if (axis == View.X_AXIS) {
1408+ value = totalColumnRequirements.minimum + getLeftInset() +
1409+ getRightInset();
1410+ }
1411+ else {
1412+ value = super.getMinimumSpan(axis);
1413+ }
1414+ return value;
1415+ }
1416+
1417+ public float getMaximumSpan(int axis) {
1418+ float value;
1419+
1420+ if (axis == View.X_AXIS) {
1421+ // We're flexible.
1422+ value = (float)Integer.MAX_VALUE;
1423+ }
1424+ else {
1425+ value = super.getMaximumSpan(axis);
1426+ }
1427+ return value;
1428+ }
1429+
1430+ public float getPreferredSpan(int axis) {
1431+ float value;
1432+
1433+ if (axis == View.X_AXIS) {
1434+ value = totalColumnRequirements.preferred + getLeftInset() +
1435+ getRightInset();
1436+ }
1437+ else {
1438+ value = super.getPreferredSpan(axis);
1439+ }
1440+ return value;
1441+ }
1442+
1443+ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
1444+ super.changedUpdate(e, a, f);
1445+ int pos = e.getOffset();
1446+ if (pos <= getStartOffset() && (pos + e.getLength()) >=
1447+ getEndOffset()) {
1448+ RowView.this.setPropertiesFromAttributes();
1449+ }
1450+ }
1451+
1452+ /**
1453+ * Renders using the given rendering surface and area on that
1454+ * surface. This is implemented to delegate to the css box
1455+ * painter to paint the border and background prior to the
1456+ * interior.
1457+ *
1458+ * @param g the rendering surface to use
1459+ * @param allocation the allocated region to render into
1460+ * @see View#paint
1461+ */
1462+ public void paint(Graphics g, Shape allocation) {
1463+ Rectangle a = (Rectangle) allocation;
1464+ painter.paint(g, a.x, a.y, a.width, a.height, this);
1465+ super.paint(g, a);
1466+ }
1467+
1468+ /**
1469+ * Change the child views. This is implemented to
1470+ * provide the superclass behavior and invalidate the
1471+ * grid so that rows and columns will be recalculated.
1472+ */
1473+ public void replace(int offset, int length, View[] views) {
1474+ super.replace(offset, length, views);
1475+ invalidateGrid();
1476+ }
1477+
1478+ /**
1479+ * Calculate the height requirements of the table row. The
1480+ * requirements of multi-row cells are not considered for this
1481+ * calculation. The table itself will check and adjust the row
1482+ * requirements for all the rows that have multi-row cells spanning
1483+ * them. This method updates the multi-row flag that indicates that
1484+ * this row and rows below need additional consideration.
1485+ */
1486+ protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
1487+// return super.calculateMinorAxisRequirements(axis, r);
1488+ long min = 0;
1489+ long pref = 0;
1490+ long max = 0;
1491+ multiRowCells = false;
1492+ int n = getViewCount();
1493+ for (int i = 0; i < n; i++) {
1494+ View v = getView(i);
1495+ if (getRowsOccupied(v) > 1) {
1496+ multiRowCells = true;
1497+ max = Math.max((int) v.getMaximumSpan(axis), max);
1498+ } else {
1499+ min = Math.max((int) v.getMinimumSpan(axis), min);
1500+ pref = Math.max((int) v.getPreferredSpan(axis), pref);
1501+ max = Math.max((int) v.getMaximumSpan(axis), max);
1502+ }
1503+ }
1504+
1505+ if (r == null) {
1506+ r = new SizeRequirements();
1507+ r.alignment = 0.5f;
1508+ }
1509+ r.preferred = (int) pref;
1510+ r.minimum = (int) min;
1511+ r.maximum = (int) max;
1512+ return r;
1513+ }
1514+
1515+ /**
1516+ * Perform layout for the major axis of the box (i.e. the
1517+ * axis that it represents). The results of the layout should
1518+ * be placed in the given arrays which represent the allocations
1519+ * to the children along the major axis.
1520+ * <p>
1521+ * This is re-implemented to give each child the span of the column
1522+ * width for the table, and to give cells that span multiple columns
1523+ * the multi-column span.
1524+ *
1525+ * @param targetSpan the total span given to the view, which
1526+ * whould be used to layout the children
1527+ * @param axis the axis being layed out
1528+ * @param offsets the offsets from the origin of the view for
1529+ * each of the child views; this is a return value and is
1530+ * filled in by the implementation of this method
1531+ * @param spans the span of each child view; this is a return
1532+ * value and is filled in by the implementation of this method
1533+ * @return the offset and span for each child view in the
1534+ * offsets and spans parameters
1535+ */
1536+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1537+ int col = 0;
1538+ int ncells = getViewCount();
1539+ for (int cell = 0; cell < ncells; cell++) {
1540+ View cv = getView(cell);
1541+ if (skipComments && !(cv instanceof CellView)) {
1542+ continue;
1543+ }
1544+ for (; isFilled(col); col++); // advance to a free column
1545+ int colSpan = getColumnsOccupied(cv);
1546+ spans[cell] = columnSpans[col];
1547+ offsets[cell] = columnOffsets[col];
1548+ if (colSpan > 1) {
1549+ int n = columnSpans.length;
1550+ for (int j = 1; j < colSpan; j++) {
1551+ // Because the table may be only partially formed, some
1552+ // of the columns may not yet exist. Therefore we check
1553+ // the bounds.
1554+ if ((col+j) < n) {
1555+ spans[cell] += columnSpans[col+j];
1556+ spans[cell] += cellSpacing;
1557+ }
1558+ }
1559+ col += colSpan - 1;
1560+ }
1561+ col++;
1562+ }
1563+ }
1564+
1565+ /**
1566+ * Perform layout for the minor axis of the box (i.e. the
1567+ * axis orthoginal to the axis that it represents). The results
1568+ * of the layout should be placed in the given arrays which represent
1569+ * the allocations to the children along the minor axis. This
1570+ * is called by the superclass whenever the layout needs to be
1571+ * updated along the minor axis.
1572+ * <p>
1573+ * This is implemented to delegate to the superclass, then adjust
1574+ * the span for any cell that spans multiple rows.
1575+ *
1576+ * @param targetSpan the total span given to the view, which
1577+ * whould be used to layout the children
1578+ * @param axis the axis being layed out
1579+ * @param offsets the offsets from the origin of the view for
1580+ * each of the child views; this is a return value and is
1581+ * filled in by the implementation of this method
1582+ * @param spans the span of each child view; this is a return
1583+ * value and is filled in by the implementation of this method
1584+ * @return the offset and span for each child view in the
1585+ * offsets and spans parameters
1586+ */
1587+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1588+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
1589+ int col = 0;
1590+ int ncells = getViewCount();
1591+ for (int cell = 0; cell < ncells; cell++, col++) {
1592+ View cv = getView(cell);
1593+ for (; isFilled(col); col++); // advance to a free column
1594+ int colSpan = getColumnsOccupied(cv);
1595+ int rowSpan = getRowsOccupied(cv);
1596+ if (rowSpan > 1) {
1597+
1598+ int row0 = rowIndex;
1599+ int row1 = Math.min(rowIndex + rowSpan - 1, getRowCount()-1);
1600+ spans[cell] = getMultiRowSpan(row0, row1);
1601+ }
1602+ if (colSpan > 1) {
1603+ col += colSpan - 1;
1604+ }
1605+ }
1606+ }
1607+
1608+ /**
1609+ * Determines the resizability of the view along the
1610+ * given axis. A value of 0 or less is not resizable.
1611+ *
1612+ * @param axis may be either View.X_AXIS or View.Y_AXIS
1613+ * @return the resize weight
1614+ * @exception IllegalArgumentException for an invalid axis
1615+ */
1616+ public int getResizeWeight(int axis) {
1617+ return 1;
1618+ }
1619+
1620+ /**
1621+ * Fetches the child view that represents the given position in
1622+ * the model. This is implemented to walk through the children
1623+ * looking for a range that contains the given position. In this
1624+ * view the children do not necessarily have a one to one mapping
1625+ * with the child elements.
1626+ *
1627+ * @param pos the search position >= 0
1628+ * @param a the allocation to the table on entry, and the
1629+ * allocation of the view containing the position on exit
1630+ * @return the view representing the given position, or
1631+ * null if there isn't one
1632+ */
1633+ protected View getViewAtPosition(int pos, Rectangle a) {
1634+ int n = getViewCount();
1635+ for (int i = 0; i < n; i++) {
1636+ View v = getView(i);
1637+ int p0 = v.getStartOffset();
1638+ int p1 = v.getEndOffset();
1639+ if ((pos >= p0) && (pos < p1)) {
1640+ // it's in this view.
1641+ if (a != null) {
1642+ childAllocation(i, a);
1643+ }
1644+ return v;
1645+ }
1646+ }
1647+ if (pos == getEndOffset()) {
1648+ View v = getView(n - 1);
1649+ if (a != null) {
1650+ this.childAllocation(n - 1, a);
1651+ }
1652+ return v;
1653+ }
1654+ return null;
1655+ }
1656+
1657+ /**
1658+ * Update any cached values that come from attributes.
1659+ */
1660+ void setPropertiesFromAttributes() {
1661+ StyleSheet sheet = getStyleSheet();
1662+ attr = sheet.getViewAttributes(this);
1663+ painter = sheet.getBoxPainter(attr);
1664+ }
1665+
1666+ private StyleSheet.BoxPainter painter;
1667+ private AttributeSet attr;
1668+
1669+ /** columns filled by multi-column or multi-row cells */
1670+ BitSet fillColumns;
1671+
1672+ /**
1673+ * The row index within the overall grid
1674+ */
1675+ int rowIndex;
1676+
1677+ /**
1678+ * The view index (for row index to view index conversion).
1679+ * This is set by the updateGrid method.
1680+ */
1681+ int viewIndex;
1682+
1683+ /**
1684+ * Does this table row have cells that span multiple rows?
1685+ */
1686+ boolean multiRowCells;
1687+
1688+ }
1689+
1690+ /**
1691+ * Default view of an html table cell. This needs to be moved
1692+ * somewhere else.
1693+ */
1694+ class CellView extends BlockView {
1695+
1696+ /**
1697+ * Constructs a TableCell for the given element.
1698+ *
1699+ * @param elem the element that this view is responsible for
1700+ */
1701+ public CellView(Element elem) {
1702+ super(elem, Y_AXIS);
1703+ }
1704+
1705+ /**
1706+ * Perform layout for the major axis of the box (i.e. the
1707+ * axis that it represents). The results of the layout should
1708+ * be placed in the given arrays which represent the allocations
1709+ * to the children along the major axis. This is called by the
1710+ * superclass to recalculate the positions of the child views
1711+ * when the layout might have changed.
1712+ * <p>
1713+ * This is implemented to delegate to the superclass to
1714+ * tile the children. If the target span is greater than
1715+ * was needed, the offsets are adjusted to align the children
1716+ * (i.e. position according to the html valign attribute).
1717+ *
1718+ * @param targetSpan the total span given to the view, which
1719+ * whould be used to layout the children
1720+ * @param axis the axis being layed out
1721+ * @param offsets the offsets from the origin of the view for
1722+ * each of the child views; this is a return value and is
1723+ * filled in by the implementation of this method
1724+ * @param spans the span of each child view; this is a return
1725+ * value and is filled in by the implementation of this method
1726+ * @return the offset and span for each child view in the
1727+ * offsets and spans parameters
1728+ */
1729+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1730+ super.layoutMajorAxis(targetSpan, axis, offsets, spans);
1731+ // calculate usage
1732+ int used = 0;
1733+ int n = spans.length;
1734+ for (int i = 0; i < n; i++) {
1735+ used += spans[i];
1736+ }
1737+
1738+ // calculate adjustments
1739+ int adjust = 0;
1740+ if (used < targetSpan) {
1741+ // PENDING(prinz) change to use the css alignment.
1742+ String valign = (String) getElement().getAttributes().getAttribute(
1743+ HTML.Attribute.VALIGN);
1744+ if (valign == null) {
1745+ AttributeSet rowAttr = getElement().getParentElement().getAttributes();
1746+ valign = (String) rowAttr.getAttribute(HTML.Attribute.VALIGN);
1747+ }
1748+ if ((valign == null) || valign.equals("middle")) {
1749+ adjust = (targetSpan - used) / 2;
1750+ } else if (valign.equals("bottom")) {
1751+ adjust = targetSpan - used;
1752+ }
1753+ }
1754+
1755+ // make adjustments.
1756+ if (adjust != 0) {
1757+ for (int i = 0; i < n; i++) {
1758+ offsets[i] += adjust;
1759+ }
1760+ }
1761+ }
1762+
1763+ /**
1764+ * Calculate the requirements needed along the major axis.
1765+ * This is called by the superclass whenever the requirements
1766+ * need to be updated (i.e. a preferenceChanged was messaged
1767+ * through this view).
1768+ * <p>
1769+ * This is implemented to delegate to the superclass, but
1770+ * indicate the maximum size is very large (i.e. the cell
1771+ * is willing to expend to occupy the full height of the row).
1772+ *
1773+ * @param axis the axis being layed out.
1774+ * @param r the requirements to fill in. If null, a new one
1775+ * should be allocated.
1776+ */
1777+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
1778+ SizeRequirements r) {
1779+ SizeRequirements req = super.calculateMajorAxisRequirements(axis, r);
1780+ req.maximum = Integer.MAX_VALUE;
1781+ return req;
1782+ }
1783+
1784+ @Override
1785+ protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
1786+ SizeRequirements rv = super.calculateMinorAxisRequirements(axis, r);
1787+ //for the cell the minimum should be derived from the child views
1788+ //the parent behaviour is to use CSS for that
1789+ int n = getViewCount();
1790+ int min = 0;
1791+ for (int i = 0; i < n; i++) {
1792+ View v = getView(i);
1793+ min = Math.max((int) v.getMinimumSpan(axis), min);
1794+ }
1795+ rv.minimum = Math.min(rv.minimum, min);
1796+ return rv;
1797+ }
1798+ }
1799+
1800+
1801+}