KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > html > TableView


1 /*
2  * @(#)TableView.java 1.39 06/06/30
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text.html;
8
9 import java.awt.*;
10 import java.util.BitSet JavaDoc;
11 import java.util.Vector JavaDoc;
12 import java.util.Arrays JavaDoc;
13 import javax.swing.SizeRequirements JavaDoc;
14 import javax.swing.event.DocumentEvent JavaDoc;
15
16 import javax.swing.text.*;
17
18 /**
19  * HTML table view.
20  *
21  * @author Timothy Prinzing
22  * @version 1.39 06/30/06
23  * @see View
24  */

25 /*public*/ class TableView extends BoxView implements ViewFactory {
26
27     /**
28      * Constructs a TableView for the given element.
29      *
30      * @param elem the element that this view is responsible for
31      */

32     public TableView(Element elem) {
33     super(elem, View.Y_AXIS);
34     rows = new Vector JavaDoc();
35     gridValid = false;
36     captionIndex = -1;
37         totalColumnRequirements = new SizeRequirements JavaDoc();
38     }
39
40     /**
41      * Creates a new table row.
42      *
43      * @param elem an element
44      * @return the row
45      */

46     protected RowView createTableRow(Element elem) {
47     // PENDING(prinz) need to add support for some of the other
48
// elements, but for now just ignore anything that is not
49
// a TR.
50
Object JavaDoc o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
51     if (o == HTML.Tag.TR) {
52         return new RowView(elem);
53     }
54     return null;
55     }
56
57     /**
58      * The number of columns in the table.
59      */

60     public int getColumnCount() {
61     return columnSpans.length;
62     }
63
64     /**
65      * Fetches the span (width) of the given column.
66      * This is used by the nested cells to query the
67      * sizes of grid locations outside of themselves.
68      */

69     public int getColumnSpan(int col) {
70     if (col < columnSpans.length) {
71         return columnSpans[col];
72     }
73     return 0;
74     }
75
76     /**
77      * The number of rows in the table.
78      */

79     public int getRowCount() {
80     return rows.size();
81     }
82
83     /**
84      * Fetch the span of multiple rows. This includes
85      * the border area.
86      */

87     public int getMultiRowSpan(int row0, int row1) {
88     RowView rv0 = getRow(row0);
89     RowView rv1 = getRow(row1);
90     if ((rv0 != null) && (rv1 != null)) {
91         int index0 = rv0.viewIndex;
92         int index1 = rv1.viewIndex;
93         int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) +
94         getSpan(Y_AXIS, index1);
95         return span;
96     }
97     return 0;
98     }
99
100     /**
101      * Fetches the span (height) of the given row.
102      */

103     public int getRowSpan(int row) {
104     RowView rv = getRow(row);
105     if (rv != null) {
106         return getSpan(Y_AXIS, rv.viewIndex);
107     }
108     return 0;
109     }
110
111     RowView getRow(int row) {
112     if (row < rows.size()) {
113         return (RowView) rows.elementAt(row);
114     }
115     return null;
116     }
117
118     protected View getViewAtPoint(int x, int y, Rectangle alloc) {
119     int n = getViewCount();
120     View v = null;
121     Rectangle allocation = new Rectangle();
122     for (int i = 0; i < n; i++) {
123         allocation.setBounds(alloc);
124         childAllocation(i, allocation);
125         v = getView(i);
126         if (v instanceof RowView) {
127         v = ((RowView)v).findViewAtPoint(x, y, allocation);
128         if (v != null) {
129             alloc.setBounds(allocation);
130             return v;
131         }
132         }
133     }
134         return super.getViewAtPoint(x, y, alloc);
135     }
136
137     /**
138      * Determines the number of columns occupied by
139      * the table cell represented by given element.
140      */

141     protected int getColumnsOccupied(View v) {
142     AttributeSet a = v.getElement().getAttributes();
143
144         if (a.isDefined(HTML.Attribute.COLSPAN)) {
145             String JavaDoc s = (String JavaDoc) a.getAttribute(HTML.Attribute.COLSPAN);
146             if (s != null) {
147                 try {
148                     return Integer.parseInt(s);
149                 } catch (NumberFormatException JavaDoc nfe) {
150                     // fall through to one column
151
}
152             }
153         }
154
155     return 1;
156     }
157
158     /**
159      * Determines the number of rows occupied by
160      * the table cell represented by given element.
161      */

162     protected int getRowsOccupied(View v) {
163     AttributeSet a = v.getElement().getAttributes();
164
165         if (a.isDefined(HTML.Attribute.ROWSPAN)) {
166             String JavaDoc s = (String JavaDoc) a.getAttribute(HTML.Attribute.ROWSPAN);
167             if (s != null) {
168                 try {
169                     return Integer.parseInt(s);
170                 } catch (NumberFormatException JavaDoc nfe) {
171                     // fall through to one row
172
}
173             }
174         }
175
176     return 1;
177     }
178
179     protected void invalidateGrid() {
180     gridValid = false;
181     }
182
183     protected StyleSheet JavaDoc getStyleSheet() {
184     HTMLDocument JavaDoc doc = (HTMLDocument JavaDoc) getDocument();
185     return doc.getStyleSheet();
186     }
187
188     /**
189      * Update the insets, which contain the caption if there
190      * is a caption.
191      */

192     void updateInsets() {
193     short top = (short) painter.getInset(TOP, this);
194     short bottom = (short) painter.getInset(BOTTOM, this);
195     if (captionIndex != -1) {
196         View caption = getView(captionIndex);
197         short h = (short) caption.getPreferredSpan(Y_AXIS);
198         AttributeSet a = caption.getAttributes();
199         Object JavaDoc align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);
200         if ((align != null) && (align.equals("bottom"))) {
201         bottom += h;
202         } else {
203         top += h;
204         }
205     }
206     setInsets(top, (short) painter.getInset(LEFT, this),
207           bottom, (short) painter.getInset(RIGHT, this));
208     }
209
210     /**
211      * Update any cached values that come from attributes.
212      */

213     protected void setPropertiesFromAttributes() {
214     StyleSheet JavaDoc sheet = getStyleSheet();
215     attr = sheet.getViewAttributes(this);
216     painter = sheet.getBoxPainter(attr);
217     if (attr != null) {
218         setInsets((short) painter.getInset(TOP, this),
219               (short) painter.getInset(LEFT, this),
220               (short) painter.getInset(BOTTOM, this),
221               (short) painter.getInset(RIGHT, this));
222
223         CSS.LengthValue JavaDoc lv = (CSS.LengthValue JavaDoc)
224         attr.getAttribute(CSS.Attribute.BORDER_SPACING);
225         if (lv != null) {
226         cellSpacing = (int) lv.getValue();
227         } else {
228         cellSpacing = 0;
229         }
230         lv = (CSS.LengthValue JavaDoc)
231             attr.getAttribute(CSS.Attribute.BORDER_TOP_WIDTH);
232         if (lv != null) {
233             borderWidth = (int) lv.getValue();
234         } else {
235             borderWidth = 0;
236         }
237
238         }
239     }
240
241     /**
242      * Fill in the grid locations that are placeholders
243      * for multi-column, multi-row, and missing grid
244      * locations.
245      */

246     void updateGrid() {
247     if (! gridValid) {
248         relativeCells = false;
249         multiRowCells = false;
250
251         // determine which views are table rows and clear out
252
// grid points marked filled.
253
captionIndex = -1;
254         rows.removeAllElements();
255         int n = getViewCount();
256         for (int i = 0; i < n; i++) {
257         View v = getView(i);
258         if (v instanceof RowView) {
259             rows.addElement(v);
260             RowView rv = (RowView) v;
261             rv.clearFilledColumns();
262             rv.rowIndex = rows.size() - 1;
263             rv.viewIndex = i;
264         } else {
265             Object JavaDoc o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute);
266             if (o instanceof HTML.Tag JavaDoc) {
267             HTML.Tag JavaDoc kind = (HTML.Tag JavaDoc) o;
268             if (kind == HTML.Tag.CAPTION) {
269                 captionIndex = i;
270             }
271             }
272         }
273         }
274
275         int maxColumns = 0;
276         int nrows = rows.size();
277         for (int row = 0; row < nrows; row++) {
278         RowView rv = getRow(row);
279         int col = 0;
280         for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
281             View cv = rv.getView(cell);
282             if (! relativeCells) {
283             AttributeSet a = cv.getAttributes();
284             CSS.LengthValue JavaDoc lv = (CSS.LengthValue JavaDoc)
285                 a.getAttribute(CSS.Attribute.WIDTH);
286             if ((lv != null) && (lv.isPercentage())) {
287                 relativeCells = true;
288             }
289             }
290             // advance to a free column
291
for (; rv.isFilled(col); col++);
292             int rowSpan = getRowsOccupied(cv);
293             if (rowSpan > 1) {
294             multiRowCells = true;
295             }
296             int colSpan = getColumnsOccupied(cv);
297             if ((colSpan > 1) || (rowSpan > 1)) {
298             // fill in the overflow entries for this cell
299
int rowLimit = row + rowSpan;
300             int colLimit = col + colSpan;
301             for (int i = row; i < rowLimit; i++) {
302                 for (int j = col; j < colLimit; j++) {
303                 if (i != row || j != col) {
304                     addFill(i, j);
305                 }
306                 }
307             }
308             if (colSpan > 1) {
309                 col += colSpan - 1;
310             }
311             }
312         }
313         maxColumns = Math.max(maxColumns, col);
314         }
315
316         // setup the column layout/requirements
317
columnSpans = new int[maxColumns];
318         columnOffsets = new int[maxColumns];
319         columnRequirements = new SizeRequirements JavaDoc[maxColumns];
320         for (int i = 0; i < maxColumns; i++) {
321         columnRequirements[i] = new SizeRequirements JavaDoc();
322                 columnRequirements[i].maximum = Integer.MAX_VALUE;
323         }
324         gridValid = true;
325     }
326     }
327
328     /**
329      * Mark a grid location as filled in for a cells overflow.
330      */

331     void addFill(int row, int col) {
332     RowView rv = getRow(row);
333     if (rv != null) {
334         rv.fillColumn(col);
335     }
336     }
337
338     /**
339      * Layout the columns to fit within the given target span.
340      *
341      * @param targetSpan the given span for total of all the table
342      * columns
343      * @param reqs the requirements desired for each column. This
344      * is the column maximum of the cells minimum, preferred, and
345      * maximum requested span
346      * @param spans the return value of how much to allocated to
347      * each column
348      * @param offsets the return value of the offset from the
349      * origin for each column
350      * @return the offset from the origin and the span for each column
351      * in the offsets and spans parameters
352      */

353     protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
354                  SizeRequirements JavaDoc[] reqs) {
355         //clean offsets and spans
356
Arrays.fill(offsets, 0);
357         Arrays.fill(spans, 0);
358     colIterator.setLayoutArrays(offsets, spans, targetSpan);
359     CSS.calculateTiledLayout(colIterator, targetSpan);
360     }
361
362     /**
363      * Calculate the requirements for each column. The calculation
364      * is done as two passes over the table. The table cells that
365      * occupy a single column are scanned first to determine the
366      * maximum of minimum, preferred, and maximum spans along the
367      * give axis. Table cells that span multiple columns are excluded
368      * from the first pass. A second pass is made to determine if
369      * the cells that span multiple columns are satisfied. If the
370      * column requirements are not satisified, the needs of the
371      * multi-column cell is mixed into the existing column requirements.
372      * The calculation of the multi-column distribution is based upon
373      * the proportions of the existing column requirements and taking
374      * into consideration any constraining maximums.
375      */

376     void calculateColumnRequirements(int axis) {
377         // clean columnRequirements
378
for (SizeRequirements JavaDoc req : columnRequirements) {
379             req.minimum = 0;
380             req.preferred = 0;
381             req.maximum = Integer.MAX_VALUE;
382         }
383     Container host = getContainer();
384     if (host != null) {
385         if (host instanceof JTextComponent) {
386         skipComments = !((JTextComponent)host).isEditable();
387         } else {
388         skipComments = true;
389         }
390     }
391     // pass 1 - single column cells
392
boolean hasMultiColumn = false;
393     int nrows = getRowCount();
394     for (int i = 0; i < nrows; i++) {
395         RowView row = getRow(i);
396         int col = 0;
397         int ncells = row.getViewCount();
398         for (int cell = 0; cell < ncells; cell++) {
399         View cv = row.getView(cell);
400         if (skipComments && !(cv instanceof CellView)) {
401             continue;
402         }
403         for (; row.isFilled(col); col++); // advance to a free column
404
int rowSpan = getRowsOccupied(cv);
405         int colSpan = getColumnsOccupied(cv);
406         if (colSpan == 1) {
407             checkSingleColumnCell(axis, col, cv);
408         } else {
409             hasMultiColumn = true;
410             col += colSpan - 1;
411         }
412         col++;
413         }
414     }
415
416     // pass 2 - multi-column cells
417
if (hasMultiColumn) {
418         for (int i = 0; i < nrows; i++) {
419         RowView row = getRow(i);
420         int col = 0;
421         int ncells = row.getViewCount();
422         for (int cell = 0; cell < ncells; cell++) {
423             View cv = row.getView(cell);
424             if (skipComments && !(cv instanceof CellView)) {
425             continue;
426             }
427             for (; row.isFilled(col); col++); // advance to a free column
428
int colSpan = getColumnsOccupied(cv);
429             if (colSpan > 1) {
430             checkMultiColumnCell(axis, col, colSpan, cv);
431             col += colSpan - 1;
432             }
433             col++;
434         }
435         }
436     }
437     }
438
439     /**
440      * check the requirements of a table cell that spans a single column.
441      */

442     void checkSingleColumnCell(int axis, int col, View v) {
443     SizeRequirements JavaDoc req = columnRequirements[col];
444     req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
445     req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
446     }
447
448     /**
449      * check the requirements of a table cell that spans multiple
450      * columns.
451      */

452     void checkMultiColumnCell(int axis, int col, int ncols, View v) {
453     // calculate the totals
454
long min = 0;
455     long pref = 0;
456     long max = 0;
457     for (int i = 0; i < ncols; i++) {
458         SizeRequirements JavaDoc req = columnRequirements[col + i];
459         min += req.minimum;
460         pref += req.preferred;
461         max += req.maximum;
462     }
463
464     // check if the minimum size needs adjustment.
465
int cmin = (int) v.getMinimumSpan(axis);
466     if (cmin > min) {
467         /*
468          * the columns that this cell spans need adjustment to fit
469          * this table cell.... calculate the adjustments.
470          */

471         SizeRequirements JavaDoc[] reqs = new SizeRequirements JavaDoc[ncols];
472         for (int i = 0; i < ncols; i++) {
473         reqs[i] = columnRequirements[col + i];
474         }
475         int[] spans = new int[ncols];
476         int[] offsets = new int[ncols];
477         SizeRequirements.calculateTiledPositions(cmin, null, reqs,
478                              offsets, spans);
479         // apply the adjustments
480
for (int i = 0; i < ncols; i++) {
481         SizeRequirements JavaDoc req = reqs[i];
482         req.minimum = Math.max(spans[i], req.minimum);
483         req.preferred = Math.max(req.minimum, req.preferred);
484         req.maximum = Math.max(req.preferred, req.maximum);
485         }
486     }
487
488     // check if the preferred size needs adjustment.
489
int cpref = (int) v.getPreferredSpan(axis);
490     if (cpref > pref) {
491         /*
492          * the columns that this cell spans need adjustment to fit
493          * this table cell.... calculate the adjustments.
494          */

495         SizeRequirements JavaDoc[] reqs = new SizeRequirements JavaDoc[ncols];
496         for (int i = 0; i < ncols; i++) {
497         reqs[i] = columnRequirements[col + i];
498         }
499         int[] spans = new int[ncols];
500         int[] offsets = new int[ncols];
501         SizeRequirements.calculateTiledPositions(cpref, null, reqs,
502                              offsets, spans);
503         // apply the adjustments
504
for (int i = 0; i < ncols; i++) {
505         SizeRequirements JavaDoc req = reqs[i];
506         req.preferred = Math.max(spans[i], req.preferred);
507         req.maximum = Math.max(req.preferred, req.maximum);
508         }
509     }
510
511     }
512
513     // --- BoxView methods -----------------------------------------
514

515     /**
516      * Calculate the requirements for the minor axis. This is called by
517      * the superclass whenever the requirements need to be updated (i.e.
518      * a preferenceChanged was messaged through this view).
519      * <p>
520      * This is implemented to calculate the requirements as the sum of the
521      * requirements of the columns and then adjust it if the
522      * CSS width or height attribute is specified and applicable to
523      * the axis.
524      */

525     protected SizeRequirements JavaDoc calculateMinorAxisRequirements(int axis, SizeRequirements JavaDoc r) {
526     updateGrid();
527     
528     // calculate column requirements for each column
529
calculateColumnRequirements(axis);
530
531
532     // the requirements are the sum of the columns.
533
if (r == null) {
534         r = new SizeRequirements JavaDoc();
535     }
536     long min = 0;
537     long pref = 0;
538     int n = columnRequirements.length;
539     for (int i = 0; i < n; i++) {
540         SizeRequirements JavaDoc req = columnRequirements[i];
541         min += req.minimum;
542         pref += req.preferred;
543     }
544     int adjust = (n + 1) * cellSpacing + 2 * borderWidth;
545     min += adjust;
546     pref += adjust;
547     r.minimum = (int) min;
548     r.preferred = (int) pref;
549     r.maximum = (int) pref;
550
551
552     AttributeSet attr = getAttributes();
553         CSS.LengthValue JavaDoc cssWidth = (CSS.LengthValue JavaDoc)attr.getAttribute(
554                                                     CSS.Attribute.WIDTH);
555
556     if (BlockView.spanSetFromAttributes(axis, r, cssWidth, null)) {
557             if (r.minimum < (int)min) {
558                 // The user has requested a smaller size than is needed to
559
// show the table, override it.
560
r.maximum = r.minimum = r.preferred = (int) min;
561             }
562         }
563         totalColumnRequirements.minimum = r.minimum;
564         totalColumnRequirements.preferred = r.preferred;
565         totalColumnRequirements.maximum = r.maximum;
566
567     // set the alignment
568
Object JavaDoc o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
569     if (o != null) {
570         // set horizontal alignment
571
String JavaDoc ta = o.toString();
572         if (ta.equals("left")) {
573         r.alignment = 0;
574         } else if (ta.equals("center")) {
575         r.alignment = 0.5f;
576         } else if (ta.equals("right")) {
577         r.alignment = 1;
578         } else {
579         r.alignment = 0;
580         }
581     } else {
582         r.alignment = 0;
583     }
584     
585     return r;
586     }
587
588     /**
589      * Calculate the requirements for the major axis. This is called by
590      * the superclass whenever the requirements need to be updated (i.e.
591      * a preferenceChanged was messaged through this view).
592      * <p>
593      * This is implemented to provide the superclass behavior adjusted for
594      * multi-row table cells.
595      */

596     protected SizeRequirements JavaDoc calculateMajorAxisRequirements(int axis, SizeRequirements JavaDoc r) {
597     updateInsets();
598     rowIterator.updateAdjustments();
599     r = CSS.calculateTiledRequirements(rowIterator, r);
600     r.maximum = r.preferred;
601     return r;
602     }
603
604     /**
605      * Perform layout for the minor axis of the box (i.e. the
606      * axis orthoginal to the axis that it represents). The results
607      * of the layout should be placed in the given arrays which represent
608      * the allocations to the children along the minor axis. This
609      * is called by the superclass whenever the layout needs to be
610      * updated along the minor axis.
611      * <p>
612      * This is implemented to call the
613      * <a HREF="#layoutColumns">layoutColumns</a> method, and then
614      * forward to the superclass to actually carry out the layout
615      * of the tables rows.
616      *
617      * @param targetSpan the total span given to the view, which
618      * whould be used to layout the children
619      * @param axis the axis being layed out
620      * @param offsets the offsets from the origin of the view for
621      * each of the child views. This is a return value and is
622      * filled in by the implementation of this method
623      * @param spans the span of each child view; this is a return
624      * value and is filled in by the implementation of this method
625      * @return the offset and span for each child view in the
626      * offsets and spans parameters
627      */

628     protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
629     // make grid is properly represented
630
updateGrid();
631
632     // all of the row layouts are invalid, so mark them that way
633
int n = getRowCount();
634     for (int i = 0; i < n; i++) {
635         RowView row = getRow(i);
636         row.layoutChanged(axis);
637     }
638
639     // calculate column spans
640
layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
641
642     // continue normal layout
643
super.layoutMinorAxis(targetSpan, axis, offsets, spans);
644     }
645
646
647     /**
648      * Perform layout for the major axis of the box (i.e. the
649      * axis that it represents). The results
650      * of the layout should be placed in the given arrays which represent
651      * the allocations to the children along the minor axis. This
652      * is called by the superclass whenever the layout needs to be
653      * updated along the minor axis.
654      * <p>
655      * This method is where the layout of the table rows within the
656      * table takes place. This method is implemented to call the use
657      * the RowIterator and the CSS collapsing tile to layout
658      * with border spacing and border collapsing capabilities.
659      *
660      * @param targetSpan the total span given to the view, which
661      * whould be used to layout the children
662      * @param axis the axis being layed out
663      * @param offsets the offsets from the origin of the view for
664      * each of the child views; this is a return value and is
665      * filled in by the implementation of this method
666      * @param spans the span of each child view; this is a return
667      * value and is filled in by the implementation of this method
668      * @return the offset and span for each child view in the
669      * offsets and spans parameters
670      */

671     protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
672     rowIterator.setLayoutArrays(offsets, spans);
673     CSS.calculateTiledLayout(rowIterator, targetSpan);
674
675     if (captionIndex != -1) {
676         // place the caption
677
View caption = getView(captionIndex);
678         int h = (int) caption.getPreferredSpan(Y_AXIS);
679         spans[captionIndex] = h;
680         short boxBottom = (short) painter.getInset(BOTTOM, this);
681         if (boxBottom != getBottomInset()) {
682         offsets[captionIndex] = targetSpan + boxBottom;
683         } else {
684         offsets[captionIndex] = - getTopInset();
685         }
686     }
687     }
688
689     /**
690      * Fetches the child view that represents the given position in
691      * the model. This is implemented to walk through the children
692      * looking for a range that contains the given position. In this
693      * view the children do not necessarily have a one to one mapping
694      * with the child elements.
695      *
696      * @param pos the search position >= 0
697      * @param a the allocation to the table on entry, and the
698      * allocation of the view containing the position on exit
699      * @return the view representing the given position, or
700      * null if there isn't one
701      */

702     protected View getViewAtPosition(int pos, Rectangle a) {
703         int n = getViewCount();
704         for (int i = 0; i < n; i++) {
705             View v = getView(i);
706             int p0 = v.getStartOffset();
707             int p1 = v.getEndOffset();
708             if ((pos >= p0) && (pos < p1)) {
709                 // it's in this view.
710
if (a != null) {
711             childAllocation(i, a);
712         }
713                 return v;
714             }
715         }
716     if (pos == getEndOffset()) {
717         View v = getView(n - 1);
718         if (a != null) {
719         this.childAllocation(n - 1, a);
720         }
721         return v;
722     }
723         return null;
724     }
725
726     // --- View methods ---------------------------------------------
727

728     /**
729      * Fetches the attributes to use when rendering. This is
730      * implemented to multiplex the attributes specified in the
731      * model with a StyleSheet.
732      */

733     public AttributeSet getAttributes() {
734     if (attr == null) {
735         StyleSheet JavaDoc sheet = getStyleSheet();
736         attr = sheet.getViewAttributes(this);
737     }
738     return attr;
739     }
740
741     /**
742      * Renders using the given rendering surface and area on that
743      * surface. This is implemented to delegate to the css box
744      * painter to paint the border and background prior to the
745      * interior. The superclass culls rendering the children
746      * that don't directly intersect the clip and the row may
747      * have cells hanging from a row above in it. The table
748      * does not use the superclass rendering behavior and instead
749      * paints all of the rows and lets the rows cull those
750      * cells not intersecting the clip region.
751      *
752      * @param g the rendering surface to use
753      * @param allocation the allocated region to render into
754      * @see View#paint
755      */

756     public void paint(Graphics g, Shape allocation) {
757     // paint the border
758
Rectangle a = allocation.getBounds();
759     setSize(a.width, a.height);
760     if (captionIndex != -1) {
761         // adjust the border for the caption
762
short top = (short) painter.getInset(TOP, this);
763         short bottom = (short) painter.getInset(BOTTOM, this);
764         if (top != getTopInset()) {
765         int h = getTopInset() - top;
766         a.y += h;
767         a.height -= h;
768         } else {
769         a.height -= getBottomInset() - bottom;
770         }
771     }
772     for (int i = borderWidth; i > 0; i--) {
773         painter.paint(g, a.x + i, a.y + i, a.width - 2 * i, a.height - 2 * i, this);
774     }
775     // paint interior
776
int n = getViewCount();
777     for (int i = 0; i < n; i++) {
778         View v = getView(i);
779         v.paint(g, getChildAllocation(i, allocation));
780     }
781     //super.paint(g, a);
782
}
783
784     /**
785      * Establishes the parent view for this view. This is
786      * guaranteed to be called before any other methods if the
787      * parent view is functioning properly.
788      * <p>
789      * This is implemented
790      * to forward to the superclass as well as call the
791      * <a HREF="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
792      * method to set the paragraph properties from the css
793      * attributes. The call is made at this time to ensure
794      * the ability to resolve upward through the parents
795      * view attributes.
796      *
797      * @param parent the new parent, or null if the view is
798      * being removed from a parent it was previously added
799      * to
800      */

801     public void setParent(View parent) {
802     super.setParent(parent);
803         if (parent != null) {
804         setPropertiesFromAttributes();
805         }
806     }
807
808     /**
809      * Fetches the ViewFactory implementation that is feeding
810      * the view hierarchy.
811      * This replaces the ViewFactory with an implementation that
812      * calls through to the createTableRow and createTableCell
813      * methods. If the element given to the factory isn't a
814      * table row or cell, the request is delegated to the factory
815      * produced by the superclass behavior.
816      *
817      * @return the factory, null if none
818      */

819     public ViewFactory getViewFactory() {
820     return this;
821     }
822
823     /**
824      * Gives notification that something was inserted into
825      * the document in a location that this view is responsible for.
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      * passed as an argument.
831      *
832      * @param e the change information from the associated document
833      * @param a the current allocation of the view
834      * @param f the factory to use to rebuild if the view has children
835      * @see View#insertUpdate
836      */

837     public void insertUpdate(DocumentEvent JavaDoc e, Shape a, ViewFactory f) {
838     super.insertUpdate(e, a, this);
839     }
840
841     /**
842      * Gives notification that something was removed from the document
843      * in a location that this view is responsible for.
844      * This replaces the ViewFactory with an implementation that
845      * calls through to the createTableRow and createTableCell
846      * methods. If the element given to the factory isn't a
847      * table row or cell, the request is delegated to the factory
848      * passed as an argument.
849      *
850      * @param e the change information from the associated document
851      * @param a the current allocation of the view
852      * @param f the factory to use to rebuild if the view has children
853      * @see View#removeUpdate
854      */

855     public void removeUpdate(DocumentEvent JavaDoc e, Shape a, ViewFactory f) {
856     super.removeUpdate(e, a, this);
857     }
858
859     /**
860      * Gives notification from the document that attributes were changed
861      * in a location that this view is responsible for.
862      * This replaces the ViewFactory with an implementation that
863      * calls through to the createTableRow and createTableCell
864      * methods. If the element given to the factory isn't a
865      * table row or cell, the request is delegated to the factory
866      * passed as an argument.
867      *
868      * @param e the change information from the associated document
869      * @param a the current allocation of the view
870      * @param f the factory to use to rebuild if the view has children
871      * @see View#changedUpdate
872      */

873     public void changedUpdate(DocumentEvent JavaDoc e, Shape a, ViewFactory f) {
874     super.changedUpdate(e, a, this);
875     }
876
877     protected void forwardUpdate(DocumentEvent.ElementChange JavaDoc ec,
878                  DocumentEvent JavaDoc e, Shape a, ViewFactory f) {
879     super.forwardUpdate(ec, e, a, f);
880     // A change in any of the table cells usually effects the whole table,
881
// so redraw it all!
882
if (a != null) {
883         Component c = getContainer();
884         if (c != null) {
885         Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
886                            a.getBounds();
887         c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
888         }
889     }
890     }
891
892     /**
893      * Change the child views. This is implemented to
894      * provide the superclass behavior and invalidate the
895      * grid so that rows and columns will be recalculated.
896      */

897     public void replace(int offset, int length, View[] views) {
898     super.replace(offset, length, views);
899     invalidateGrid();
900     }
901
902     // --- ViewFactory methods ------------------------------------------
903

904     /**
905      * The table itself acts as a factory for the various
906      * views that actually represent pieces of the table.
907      * All other factory activity is delegated to the factory
908      * returned by the parent of the table.
909      */

910     public View create(Element elem) {
911     Object JavaDoc o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
912     if (o instanceof HTML.Tag JavaDoc) {
913         HTML.Tag JavaDoc kind = (HTML.Tag JavaDoc) o;
914         if (kind == HTML.Tag.TR) {
915         return createTableRow(elem);
916         } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
917         return new CellView(elem);
918         } else if (kind == HTML.Tag.CAPTION) {
919         return new javax.swing.text.html.ParagraphView JavaDoc(elem);
920         }
921     }
922     // default is to delegate to the normal factory
923
View p = getParent();
924     if (p != null) {
925         ViewFactory f = p.getViewFactory();
926         if (f != null) {
927         return f.create(elem);
928         }
929     }
930     return null;
931     }
932     
933     // ---- variables ----------------------------------------------------
934

935     private AttributeSet attr;
936     private StyleSheet.BoxPainter JavaDoc painter;
937
938     private int cellSpacing;
939     private int borderWidth;
940
941     /**
942      * The index of the caption view if there is a caption.
943      * This has a value of -1 if there is no caption. The
944      * caption lives in the inset area of the table, and is
945      * updated with each time the grid is recalculated.
946      */

947     private int captionIndex;
948
949     /**
950      * Do any of the table cells contain a relative size
951      * specification? This is updated with each call to
952      * updateGrid(). If this is true, the ColumnIterator
953      * will do extra work to calculate relative cell
954      * specifications.
955      */

956     private boolean relativeCells;
957
958     /**
959      * Do any of the table cells span multiple rows? If
960      * true, the RowRequirementIterator will do additional
961      * work to adjust the requirements of rows spanned by
962      * a single table cell. This is updated with each call to
963      * updateGrid().
964      */

965     private boolean multiRowCells;
966
967     int[] columnSpans;
968     int[] columnOffsets;
969     /**
970      * SizeRequirements for all the columns.
971      */

972     SizeRequirements JavaDoc totalColumnRequirements;
973     SizeRequirements JavaDoc[] columnRequirements;
974
975     RowIterator rowIterator = new RowIterator();
976     ColumnIterator colIterator = new ColumnIterator();
977
978     Vector JavaDoc rows;
979
980     // whether to display comments inside table or not.
981
boolean skipComments = false;
982
983     boolean gridValid;
984     static final private BitSet JavaDoc EMPTY = new BitSet JavaDoc();
985
986     class ColumnIterator implements CSS.LayoutIterator JavaDoc {
987
988     /**
989      * Disable percentage adjustments which should only apply
990      * when calculating layout, not requirements.
991      */

992     void disablePercentages() {
993         percentages = null;
994     }
995
996     /**
997      * Update percentage adjustments if they are needed.
998      */

999     private void updatePercentagesAndAdjustmentWeights(int span) {
1000        adjustmentWeights = new int[columnRequirements.length];
1001        for (int i = 0; i < columnRequirements.length; i++) {
1002        adjustmentWeights[i] = 0;
1003        }
1004        if (relativeCells) {
1005        percentages = new int[columnRequirements.length];
1006        } else {
1007        percentages = null;
1008        }
1009        int nrows = getRowCount();
1010        for (int rowIndex = 0; rowIndex < nrows; rowIndex++) {
1011        RowView row = getRow(rowIndex);
1012        int col = 0;
1013        int ncells = row.getViewCount();
1014        for (int cell = 0; cell < ncells; cell++, col++) {
1015            View cv = row.getView(cell);
1016            for (; row.isFilled(col); col++); // advance to a free column
1017
int rowSpan = getRowsOccupied(cv);
1018            int colSpan = getColumnsOccupied(cv);
1019            AttributeSet a = cv.getAttributes();
1020            CSS.LengthValue JavaDoc lv = (CSS.LengthValue JavaDoc)
1021            a.getAttribute(CSS.Attribute.WIDTH);
1022            if ( lv != null ) {
1023            int len = (int) (lv.getValue(span) / colSpan + 0.5f);
1024            for (int i = 0; i < colSpan; i++) {
1025                if (lv.isPercentage()) {
1026                // add a percentage requirement
1027
percentages[col+i] = Math.max(percentages[col+i], len);
1028                adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight);
1029                } else {
1030                adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight - 1);
1031                }
1032            }
1033            }
1034            col += colSpan - 1;
1035        }
1036        }
1037    }
1038
1039    /**
1040     * Set the layout arrays to use for holding layout results
1041     */

1042    public void setLayoutArrays(int offsets[], int spans[], int targetSpan) {
1043        this.offsets = offsets;
1044        this.spans = spans;
1045        updatePercentagesAndAdjustmentWeights(targetSpan);
1046    }
1047
1048    // --- RequirementIterator methods -------------------
1049

1050    public int getCount() {
1051        return columnRequirements.length;
1052    }
1053
1054    public void setIndex(int i) {
1055        col = i;
1056    }
1057
1058    public void setOffset(int offs) {
1059        offsets[col] = offs;
1060    }
1061
1062    public int getOffset() {
1063        return offsets[col];
1064    }
1065
1066    public void setSpan(int span) {
1067        spans[col] = span;
1068    }
1069
1070    public int getSpan() {
1071        return spans[col];
1072    }
1073
1074    public float getMinimumSpan(float parentSpan) {
1075        // do not care for percentages, since min span can't
1076
// be less than columnRequirements[col].minimum,
1077
// but can be less than percentage value.
1078
return columnRequirements[col].minimum;
1079    }
1080
1081    public float getPreferredSpan(float parentSpan) {
1082        if ((percentages != null) && (percentages[col] != 0)) {
1083        return Math.max(percentages[col], columnRequirements[col].minimum);
1084        }
1085        return columnRequirements[col].preferred;
1086    }
1087
1088    public float getMaximumSpan(float parentSpan) {
1089        return columnRequirements[col].maximum;
1090    }
1091
1092    public float getBorderWidth() {
1093        return borderWidth;
1094    }
1095
1096
1097    public float getLeadingCollapseSpan() {
1098        return cellSpacing;
1099    }
1100
1101    public float getTrailingCollapseSpan() {
1102        return cellSpacing;
1103    }
1104
1105    public int getAdjustmentWeight() {
1106        return adjustmentWeights[col];
1107    }
1108
1109    /**
1110     * Current column index
1111     */

1112    private int col;
1113
1114    /**
1115     * percentage values (may be null since there
1116     * might not be any).
1117     */

1118    private int[] percentages;
1119
1120    private int[] adjustmentWeights;
1121
1122    private int[] offsets;
1123    private int[] spans;
1124    }
1125
1126    class RowIterator implements CSS.LayoutIterator JavaDoc {
1127
1128    RowIterator() {
1129    }
1130
1131    void updateAdjustments() {
1132        int axis = Y_AXIS;
1133        if (multiRowCells) {
1134        // adjust requirements of multi-row cells
1135
int n = getRowCount();
1136        adjustments = new int[n];
1137        for (int i = 0; i < n; i++) {
1138            RowView rv = getRow(i);
1139            if (rv.multiRowCells == true) {
1140            int ncells = rv.getViewCount();
1141            for (int j = 0; j < ncells; j++) {
1142                View v = rv.getView(j);
1143                int nrows = getRowsOccupied(v);
1144                if (nrows > 1) {
1145                int spanNeeded = (int) v.getPreferredSpan(axis);
1146                adjustMultiRowSpan(spanNeeded, nrows, i);
1147                }
1148            }
1149            }
1150        }
1151        } else {
1152        adjustments = null;
1153        }
1154    }
1155
1156    /**
1157     * Fixup preferences to accomodate a multi-row table cell
1158     * if not already covered by existing preferences. This is
1159     * a no-op if not all of the rows needed (to do this check/fixup)
1160     * have arrived yet.
1161     */

1162    void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) {
1163        if ((rowIndex + nrows) > getCount()) {
1164        // rows are missing (could be a bad rowspan specification)
1165
// or not all the rows have arrived. Do the best we can with
1166
// the current set of rows.
1167
nrows = getCount() - rowIndex;
1168        if (nrows < 1) {
1169            return;
1170        }
1171        }
1172        int span = 0;
1173        for (int i = 0; i < nrows; i++) {
1174        RowView rv = getRow(rowIndex + i);
1175        span += rv.getPreferredSpan(Y_AXIS);
1176        }
1177        if (spanNeeded > span) {
1178        int adjust = (spanNeeded - span);
1179        int rowAdjust = adjust / nrows;
1180        int firstAdjust = rowAdjust + (adjust - (rowAdjust * nrows));
1181        RowView rv = getRow(rowIndex);
1182                adjustments[rowIndex] = Math.max(adjustments[rowIndex],
1183                                                 firstAdjust);
1184        for (int i = 1; i < nrows; i++) {
1185                    adjustments[rowIndex + i] = Math.max(
1186                        adjustments[rowIndex + i], rowAdjust);
1187        }
1188        }
1189    }
1190
1191    void setLayoutArrays(int[] offsets, int[] spans) {
1192        this.offsets = offsets;
1193        this.spans = spans;
1194    }
1195
1196    // --- RequirementIterator methods -------------------
1197

1198    public void setOffset(int offs) {
1199        RowView rv = getRow(row);
1200        if (rv != null) {
1201        offsets[rv.viewIndex] = offs;
1202        }
1203    }
1204
1205    public int getOffset() {
1206        RowView rv = getRow(row);
1207        if (rv != null) {
1208        return offsets[rv.viewIndex];
1209        }
1210        return 0;
1211    }
1212
1213    public void setSpan(int span) {
1214        RowView rv = getRow(row);
1215        if (rv != null) {
1216        spans[rv.viewIndex] = span;
1217        }
1218    }
1219
1220    public int getSpan() {
1221        RowView rv = getRow(row);
1222        if (rv != null) {
1223        return spans[rv.viewIndex];
1224        }
1225        return 0;
1226    }
1227
1228    public int getCount() {
1229        return rows.size();
1230    }
1231
1232    public void setIndex(int i) {
1233        row = i;
1234    }
1235
1236    public float getMinimumSpan(float parentSpan) {
1237        return getPreferredSpan(parentSpan);
1238    }
1239
1240    public float getPreferredSpan(float parentSpan) {
1241        RowView rv = getRow(row);
1242        if (rv != null) {
1243        int adjust = (adjustments != null) ? adjustments[row] : 0;
1244        return rv.getPreferredSpan(TableView.this.getAxis()) + adjust;
1245        }
1246        return 0;
1247    }
1248
1249    public float getMaximumSpan(float parentSpan) {
1250        return getPreferredSpan(parentSpan);
1251    }
1252
1253    public float getBorderWidth() {
1254        return borderWidth;
1255    }
1256
1257    public float getLeadingCollapseSpan() {
1258        return cellSpacing;
1259    }
1260
1261    public float getTrailingCollapseSpan() {
1262        return cellSpacing;
1263    }
1264
1265    public int getAdjustmentWeight() {
1266        return 0;
1267    }
1268
1269    /**
1270     * Current row index
1271     */

1272    private int row;
1273
1274    /**
1275     * Adjustments to the row requirements to handle multi-row
1276     * table cells.
1277     */

1278    private int[] adjustments;
1279
1280    private int[] offsets;
1281    private int[] spans;
1282    }
1283
1284    /**
1285     * View of a row in a row-centric table.
1286     */

1287    public class RowView extends BoxView {
1288
1289    /**
1290     * Constructs a TableView for the given element.
1291     *
1292     * @param elem the element that this view is responsible for
1293     */

1294        public RowView(Element elem) {
1295        super(elem, View.X_AXIS);
1296        fillColumns = new BitSet JavaDoc();
1297        RowView.this.setPropertiesFromAttributes();
1298    }
1299
1300    void clearFilledColumns() {
1301        fillColumns.and(EMPTY);
1302    }
1303
1304    void fillColumn(int col) {
1305        fillColumns.set(col);
1306    }
1307
1308    boolean isFilled(int col) {
1309        return fillColumns.get(col);
1310    }
1311
1312    /**
1313     * The number of columns present in this row.
1314     */

1315    int getColumnCount() {
1316        int nfill = 0;
1317        int n = fillColumns.size();
1318        for (int i = 0; i < n; i++) {
1319        if (fillColumns.get(i)) {
1320            nfill ++;
1321        }
1322        }
1323        return getViewCount() + nfill;
1324    }
1325
1326    /**
1327     * Fetches the attributes to use when rendering. This is
1328     * implemented to multiplex the attributes specified in the
1329     * model with a StyleSheet.
1330     */

1331        public AttributeSet getAttributes() {
1332        return attr;
1333    }
1334
1335    View findViewAtPoint(int x, int y, Rectangle alloc) {
1336        int n = getViewCount();
1337        for (int i = 0; i < n; i++) {
1338        if (getChildAllocation(i, alloc).contains(x, y)) {
1339            childAllocation(i, alloc);
1340            return getView(i);
1341        }
1342        }
1343        return null;
1344    }
1345
1346        protected StyleSheet JavaDoc getStyleSheet() {
1347        HTMLDocument JavaDoc doc = (HTMLDocument JavaDoc) getDocument();
1348        return doc.getStyleSheet();
1349    }
1350
1351    /**
1352     * This is called by a child to indicate its
1353     * preferred span has changed. This is implemented to
1354     * execute the superclass behavior and well as try to
1355     * determine if a row with a multi-row cell hangs across
1356     * this row. If a multi-row cell covers this row it also
1357     * needs to propagate a preferenceChanged so that it will
1358     * recalculate the multi-row cell.
1359     *
1360     * @param child the child view
1361     * @param width true if the width preference should change
1362     * @param height true if the height preference should change
1363     */

1364        public void preferenceChanged(View child, boolean width, boolean height) {
1365        super.preferenceChanged(child, width, height);
1366        if (TableView.this.multiRowCells && height) {
1367        for (int i = rowIndex - 1; i >= 0; i--) {
1368            RowView rv = TableView.this.getRow(i);
1369            if (rv.multiRowCells) {
1370            rv.preferenceChanged(null, false, true);
1371            break;
1372            }
1373        }
1374        }
1375    }
1376
1377        // The major axis requirements for a row are dictated by the column
1378
// requirements. These methods use the value calculated by
1379
// TableView.
1380
protected SizeRequirements JavaDoc calculateMajorAxisRequirements(int axis, SizeRequirements JavaDoc r) {
1381            SizeRequirements JavaDoc req = new SizeRequirements JavaDoc();
1382            req.minimum = totalColumnRequirements.minimum;
1383            req.maximum = totalColumnRequirements.maximum;
1384            req.preferred = totalColumnRequirements.preferred;
1385            req.alignment = 0f;
1386            return req;
1387        }
1388
1389        public float getMinimumSpan(int axis) {
1390            float value;
1391
1392            if (axis == View.X_AXIS) {
1393                value = totalColumnRequirements.minimum + getLeftInset() +
1394                        getRightInset();
1395            }
1396            else {
1397                value = super.getMinimumSpan(axis);
1398            }
1399            return value;
1400        }
1401
1402        public float getMaximumSpan(int axis) {
1403            float value;
1404
1405            if (axis == View.X_AXIS) {
1406                // We're flexible.
1407
value = (float)Integer.MAX_VALUE;
1408            }
1409            else {
1410                value = super.getMaximumSpan(axis);
1411            }
1412            return value;
1413        }
1414
1415        public float getPreferredSpan(int axis) {
1416            float value;
1417
1418            if (axis == View.X_AXIS) {
1419                value = totalColumnRequirements.preferred + getLeftInset() +
1420                        getRightInset();
1421            }
1422            else {
1423                value = super.getPreferredSpan(axis);
1424            }
1425            return value;
1426        }
1427
1428    public void changedUpdate(DocumentEvent JavaDoc e, Shape a, ViewFactory f) {
1429        super.changedUpdate(e, a, f);
1430        int pos = e.getOffset();
1431        if (pos <= getStartOffset() && (pos + e.getLength()) >=
1432        getEndOffset()) {
1433        RowView.this.setPropertiesFromAttributes();
1434        }
1435    }
1436    
1437    /**
1438     * Renders using the given rendering surface and area on that
1439     * surface. This is implemented to delegate to the css box
1440     * painter to paint the border and background prior to the
1441     * interior.
1442     *
1443     * @param g the rendering surface to use
1444     * @param allocation the allocated region to render into
1445     * @see View#paint
1446     */

1447    public void paint(Graphics g, Shape allocation) {
1448        Rectangle a = (Rectangle) allocation;
1449        painter.paint(g, a.x, a.y, a.width, a.height, this);
1450        super.paint(g, a);
1451    }
1452
1453    /**
1454     * Change the child views. This is implemented to
1455     * provide the superclass behavior and invalidate the
1456     * grid so that rows and columns will be recalculated.
1457     */

1458        public void replace(int offset, int length, View[] views) {
1459        super.replace(offset, length, views);
1460        invalidateGrid();
1461    }
1462
1463    /**
1464     * Calculate the height requirements of the table row. The
1465     * requirements of multi-row cells are not considered for this
1466     * calculation. The table itself will check and adjust the row
1467     * requirements for all the rows that have multi-row cells spanning
1468     * them. This method updates the multi-row flag that indicates that
1469     * this row and rows below need additional consideration.
1470     */

1471        protected SizeRequirements JavaDoc calculateMinorAxisRequirements(int axis, SizeRequirements JavaDoc r) {
1472// return super.calculateMinorAxisRequirements(axis, r);
1473
long min = 0;
1474        long pref = 0;
1475        long max = 0;
1476        multiRowCells = false;
1477        int n = getViewCount();
1478        for (int i = 0; i < n; i++) {
1479        View v = getView(i);
1480        if (getRowsOccupied(v) > 1) {
1481            multiRowCells = true;
1482            max = Math.max((int) v.getMaximumSpan(axis), max);
1483        } else {
1484            min = Math.max((int) v.getMinimumSpan(axis), min);
1485            pref = Math.max((int) v.getPreferredSpan(axis), pref);
1486            max = Math.max((int) v.getMaximumSpan(axis), max);
1487        }
1488        }
1489
1490        if (r == null) {
1491        r = new SizeRequirements JavaDoc();
1492        r.alignment = 0.5f;
1493        }
1494        r.preferred = (int) pref;
1495        r.minimum = (int) min;
1496        r.maximum = (int) max;
1497        return r;
1498    }
1499
1500    /**
1501     * Perform layout for the major axis of the box (i.e. the
1502     * axis that it represents). The results of the layout should
1503     * be placed in the given arrays which represent the allocations
1504     * to the children along the major axis.
1505     * <p>
1506     * This is re-implemented to give each child the span of the column
1507     * width for the table, and to give cells that span multiple columns
1508     * the multi-column span.
1509     *
1510     * @param targetSpan the total span given to the view, which
1511     * whould be used to layout the children
1512     * @param axis the axis being layed out
1513     * @param offsets the offsets from the origin of the view for
1514     * each of the child views; this is a return value and is
1515     * filled in by the implementation of this method
1516     * @param spans the span of each child view; this is a return
1517     * value and is filled in by the implementation of this method
1518     * @return the offset and span for each child view in the
1519     * offsets and spans parameters
1520     */

1521        protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1522        int col = 0;
1523        int ncells = getViewCount();
1524        for (int cell = 0; cell < ncells; cell++) {
1525        View cv = getView(cell);
1526        if (skipComments && !(cv instanceof CellView)) {
1527            continue;
1528        }
1529        for (; isFilled(col); col++); // advance to a free column
1530
int colSpan = getColumnsOccupied(cv);
1531        spans[cell] = columnSpans[col];
1532        offsets[cell] = columnOffsets[col];
1533        if (colSpan > 1) {
1534            int n = columnSpans.length;
1535            for (int j = 1; j < colSpan; j++) {
1536            // Because the table may be only partially formed, some
1537
// of the columns may not yet exist. Therefore we check
1538
// the bounds.
1539
if ((col+j) < n) {
1540                spans[cell] += columnSpans[col+j];
1541                spans[cell] += cellSpacing;
1542            }
1543            }
1544            col += colSpan - 1;
1545        }
1546        col++;
1547        }
1548    }
1549
1550    /**
1551     * Perform layout for the minor axis of the box (i.e. the
1552     * axis orthoginal to the axis that it represents). The results
1553     * of the layout should be placed in the given arrays which represent
1554     * the allocations to the children along the minor axis. This
1555     * is called by the superclass whenever the layout needs to be
1556     * updated along the minor axis.
1557     * <p>
1558     * This is implemented to delegate to the superclass, then adjust
1559     * the span for any cell that spans multiple rows.
1560     *
1561     * @param targetSpan the total span given to the view, which
1562     * whould be used to layout the children
1563     * @param axis the axis being layed out
1564     * @param offsets the offsets from the origin of the view for
1565     * each of the child views; this is a return value and is
1566     * filled in by the implementation of this method
1567     * @param spans the span of each child view; this is a return
1568     * value and is filled in by the implementation of this method
1569     * @return the offset and span for each child view in the
1570     * offsets and spans parameters
1571     */

1572        protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1573        super.layoutMinorAxis(targetSpan, axis, offsets, spans);
1574        int col = 0;
1575        int ncells = getViewCount();
1576        for (int cell = 0; cell < ncells; cell++, col++) {
1577        View cv = getView(cell);
1578        for (; isFilled(col); col++); // advance to a free column
1579
int colSpan = getColumnsOccupied(cv);
1580        int rowSpan = getRowsOccupied(cv);
1581        if (rowSpan > 1) {
1582            
1583            int row0 = rowIndex;
1584            int row1 = Math.min(rowIndex + rowSpan - 1, getRowCount()-1);
1585            spans[cell] = getMultiRowSpan(row0, row1);
1586        }
1587        if (colSpan > 1) {
1588            col += colSpan - 1;
1589        }
1590        }
1591    }
1592
1593    /**
1594     * Determines the resizability of the view along the
1595     * given axis. A value of 0 or less is not resizable.
1596     *
1597     * @param axis may be either View.X_AXIS or View.Y_AXIS
1598     * @return the resize weight
1599     * @exception IllegalArgumentException for an invalid axis
1600     */

1601        public int getResizeWeight(int axis) {
1602        return 1;
1603    }
1604
1605    /**
1606     * Fetches the child view that represents the given position in
1607     * the model. This is implemented to walk through the children
1608     * looking for a range that contains the given position. In this
1609     * view the children do not necessarily have a one to one mapping
1610     * with the child elements.
1611     *
1612     * @param pos the search position >= 0
1613     * @param a the allocation to the table on entry, and the
1614     * allocation of the view containing the position on exit
1615     * @return the view representing the given position, or
1616     * null if there isn't one
1617     */

1618        protected View getViewAtPosition(int pos, Rectangle a) {
1619        int n = getViewCount();
1620        for (int i = 0; i < n; i++) {
1621        View v = getView(i);
1622        int p0 = v.getStartOffset();
1623        int p1 = v.getEndOffset();
1624        if ((pos >= p0) && (pos < p1)) {
1625            // it's in this view.
1626
if (a != null) {
1627            childAllocation(i, a);
1628            }
1629            return v;
1630        }
1631        }
1632        if (pos == getEndOffset()) {
1633        View v = getView(n - 1);
1634        if (a != null) {
1635            this.childAllocation(n - 1, a);
1636        }
1637        return v;
1638        }
1639        return null;
1640    }
1641
1642    /**
1643     * Update any cached values that come from attributes.
1644     */

1645    void setPropertiesFromAttributes() {
1646        StyleSheet JavaDoc sheet = getStyleSheet();
1647        attr = sheet.getViewAttributes(this);
1648        painter = sheet.getBoxPainter(attr);
1649    }
1650
1651    private StyleSheet.BoxPainter JavaDoc painter;
1652        private AttributeSet attr;
1653
1654    /** columns filled by multi-column or multi-row cells */
1655    BitSet JavaDoc fillColumns;
1656
1657    /**
1658     * The row index within the overall grid
1659     */

1660    int rowIndex;
1661
1662    /**
1663     * The view index (for row index to view index conversion).
1664     * This is set by the updateGrid method.
1665     */

1666    int viewIndex;
1667
1668    /**
1669     * Does this table row have cells that span multiple rows?
1670     */

1671    boolean multiRowCells;
1672
1673    }
1674
1675    /**
1676     * Default view of an html table cell. This needs to be moved
1677     * somewhere else.
1678     */

1679    class CellView extends BlockView JavaDoc {
1680
1681    /**
1682     * Constructs a TableCell for the given element.
1683     *
1684     * @param elem the element that this view is responsible for
1685     */

1686        public CellView(Element elem) {
1687        super(elem, Y_AXIS);
1688    }
1689
1690    /**
1691     * Perform layout for the major axis of the box (i.e. the
1692     * axis that it represents). The results of the layout should
1693     * be placed in the given arrays which represent the allocations
1694     * to the children along the major axis. This is called by the
1695     * superclass to recalculate the positions of the child views
1696     * when the layout might have changed.
1697     * <p>
1698     * This is implemented to delegate to the superclass to
1699     * tile the children. If the target span is greater than
1700     * was needed, the offsets are adjusted to align the children
1701     * (i.e. position according to the html valign attribute).
1702     *
1703     * @param targetSpan the total span given to the view, which
1704     * whould be used to layout the children
1705     * @param axis the axis being layed out
1706     * @param offsets the offsets from the origin of the view for
1707     * each of the child views; this is a return value and is
1708     * filled in by the implementation of this method
1709     * @param spans the span of each child view; this is a return
1710     * value and is filled in by the implementation of this method
1711     * @return the offset and span for each child view in the
1712     * offsets and spans parameters
1713     */

1714        protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
1715        super.layoutMajorAxis(targetSpan, axis, offsets, spans);
1716
1717        // calculate usage
1718
int used = 0;
1719        int n = spans.length;
1720        for (int i = 0; i < n; i++) {
1721        used += spans[i];
1722        }
1723
1724        // calculate adjustments
1725
int adjust = 0;
1726        if (used < targetSpan) {
1727        // PENDING(prinz) change to use the css alignment.
1728
String JavaDoc valign = (String JavaDoc) getElement().getAttributes().getAttribute(
1729            HTML.Attribute.VALIGN);
1730        if (valign == null) {
1731            AttributeSet rowAttr = getElement().getParentElement().getAttributes();
1732            valign = (String JavaDoc) rowAttr.getAttribute(HTML.Attribute.VALIGN);
1733        }
1734        if ((valign == null) || valign.equals("middle")) {
1735            adjust = (targetSpan - used) / 2;
1736        } else if (valign.equals("bottom")) {
1737            adjust = targetSpan - used;
1738        }
1739        }
1740
1741        // make adjustments.
1742
if (adjust != 0) {
1743        for (int i = 0; i < n; i++) {
1744            offsets[i] += adjust;
1745        }
1746        }
1747    }
1748
1749    /**
1750     * Calculate the requirements needed along the major axis.
1751     * This is called by the superclass whenever the requirements
1752     * need to be updated (i.e. a preferenceChanged was messaged
1753     * through this view).
1754     * <p>
1755     * This is implemented to delegate to the superclass, but
1756     * indicate the maximum size is very large (i.e. the cell
1757     * is willing to expend to occupy the full height of the row).
1758     *
1759     * @param axis the axis being layed out.
1760     * @param r the requirements to fill in. If null, a new one
1761     * should be allocated.
1762     */

1763        protected SizeRequirements JavaDoc calculateMajorAxisRequirements(int axis,
1764                                  SizeRequirements JavaDoc r) {
1765        SizeRequirements JavaDoc req = super.calculateMajorAxisRequirements(axis, r);
1766        req.maximum = Integer.MAX_VALUE;
1767        return req;
1768    }
1769
1770        @Override JavaDoc
1771        protected SizeRequirements JavaDoc calculateMinorAxisRequirements(int axis, SizeRequirements JavaDoc r) {
1772            SizeRequirements JavaDoc rv = super.calculateMinorAxisRequirements(axis, r);
1773            //for the cell the minimum should be derived from the child views
1774
//the parent behaviour is to use CSS for that
1775
int n = getViewCount();
1776            int min = 0;
1777            for (int i = 0; i < n; i++) {
1778                View v = getView(i);
1779                min = Math.max((int) v.getMinimumSpan(axis), min);
1780            }
1781            rv.minimum = Math.min(rv.minimum, min);
1782            return rv;
1783        }
1784    }
1785
1786}
1787
Popular Tags