|
1 /* |
|
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 package javax.swing.text; |
|
26 |
|
27 import java.awt.*; |
|
28 import java.util.BitSet; |
|
29 import java.util.Vector; |
|
30 import javax.swing.SizeRequirements; |
|
31 import javax.swing.event.DocumentEvent; |
|
32 |
|
33 import javax.swing.text.html.HTML; |
|
34 |
|
35 /** |
|
36 * <p> |
|
37 * Implements View interface for a table, that is composed of an |
|
38 * element structure where the child elements of the element |
|
39 * this view is responsible for represent rows and the child |
|
40 * elements of the row elements are cells. The cell elements can |
|
41 * have an arbitrary element structure under them, which will |
|
42 * be built with the ViewFactory returned by the getViewFactory |
|
43 * method. |
|
44 * <pre> |
|
45 * |
|
46 * TABLE |
|
47 * ROW |
|
48 * CELL |
|
49 * CELL |
|
50 * ROW |
|
51 * CELL |
|
52 * CELL |
|
53 * |
|
54 * </pre> |
|
55 * <p> |
|
56 * This is implemented as a hierarchy of boxes, the table itself |
|
57 * is a vertical box, the rows are horizontal boxes, and the cells |
|
58 * are vertical boxes. The cells are allowed to span multiple |
|
59 * columns and rows. By default, the table can be thought of as |
|
60 * being formed over a grid (i.e. somewhat like one would find in |
|
61 * gridbag layout), where table cells can request to span more |
|
62 * than one grid cell. The default horizontal span of table cells |
|
63 * will be based upon this grid, but can be changed by reimplementing |
|
64 * the requested span of the cell (i.e. table cells can have independant |
|
65 * spans if desired). |
|
66 * |
|
67 * @author Timothy Prinzing |
|
68 * @see View |
|
69 */ |
|
70 public abstract class TableView extends BoxView { |
|
71 |
|
72 /** |
|
73 * Constructs a TableView for the given element. |
|
74 * |
|
75 * @param elem the element that this view is responsible for |
|
76 */ |
|
77 public TableView(Element elem) { |
|
78 super(elem, View.Y_AXIS); |
|
79 rows = new Vector(); |
|
80 gridValid = false; |
|
81 } |
|
82 |
|
83 /** |
|
84 * Creates a new table row. |
|
85 * |
|
86 * @param elem an element |
|
87 * @return the row |
|
88 */ |
|
89 protected TableRow createTableRow(Element elem) { |
|
90 return new TableRow(elem); |
|
91 } |
|
92 |
|
93 /** |
|
94 * @deprecated Table cells can now be any arbitrary |
|
95 * View implementation and should be produced by the |
|
96 * ViewFactory rather than the table. |
|
97 * |
|
98 * @param elem an element |
|
99 * @return the cell |
|
100 */ |
|
101 @Deprecated |
|
102 protected TableCell createTableCell(Element elem) { |
|
103 return new TableCell(elem); |
|
104 } |
|
105 |
|
106 /** |
|
107 * The number of columns in the table. |
|
108 */ |
|
109 int getColumnCount() { |
|
110 return columnSpans.length; |
|
111 } |
|
112 |
|
113 /** |
|
114 * Fetches the span (width) of the given column. |
|
115 * This is used by the nested cells to query the |
|
116 * sizes of grid locations outside of themselves. |
|
117 */ |
|
118 int getColumnSpan(int col) { |
|
119 return columnSpans[col]; |
|
120 } |
|
121 |
|
122 /** |
|
123 * The number of rows in the table. |
|
124 */ |
|
125 int getRowCount() { |
|
126 return rows.size(); |
|
127 } |
|
128 |
|
129 /** |
|
130 * Fetches the span (height) of the given row. |
|
131 */ |
|
132 int getRowSpan(int row) { |
|
133 View rv = getRow(row); |
|
134 if (rv != null) { |
|
135 return (int) rv.getPreferredSpan(Y_AXIS); |
|
136 } |
|
137 return 0; |
|
138 } |
|
139 |
|
140 TableRow getRow(int row) { |
|
141 if (row < rows.size()) { |
|
142 return (TableRow) rows.elementAt(row); |
|
143 } |
|
144 return null; |
|
145 } |
|
146 |
|
147 /** |
|
148 * Determines the number of columns occupied by |
|
149 * the table cell represented by given element. |
|
150 */ |
|
151 /*protected*/ int getColumnsOccupied(View v) { |
|
152 // PENDING(prinz) this code should be in the html |
|
153 // paragraph, but we can't add api to enable it. |
|
154 AttributeSet a = v.getElement().getAttributes(); |
|
155 String s = (String) a.getAttribute(HTML.Attribute.COLSPAN); |
|
156 if (s != null) { |
|
157 try { |
|
158 return Integer.parseInt(s); |
|
159 } catch (NumberFormatException nfe) { |
|
160 // fall through to one column |
|
161 } |
|
162 } |
|
163 |
|
164 return 1; |
|
165 } |
|
166 |
|
167 /** |
|
168 * Determines the number of rows occupied by |
|
169 * the table cell represented by given element. |
|
170 */ |
|
171 /*protected*/ int getRowsOccupied(View v) { |
|
172 // PENDING(prinz) this code should be in the html |
|
173 // paragraph, but we can't add api to enable it. |
|
174 AttributeSet a = v.getElement().getAttributes(); |
|
175 String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN); |
|
176 if (s != null) { |
|
177 try { |
|
178 return Integer.parseInt(s); |
|
179 } catch (NumberFormatException nfe) { |
|
180 // fall through to one row |
|
181 } |
|
182 } |
|
183 |
|
184 return 1; |
|
185 } |
|
186 |
|
187 /*protected*/ void invalidateGrid() { |
|
188 gridValid = false; |
|
189 } |
|
190 |
|
191 protected void forwardUpdate(DocumentEvent.ElementChange ec, |
|
192 DocumentEvent e, Shape a, ViewFactory f) { |
|
193 super.forwardUpdate(ec, e, a, f); |
|
194 // A change in any of the table cells usually effects the whole table, |
|
195 // so redraw it all! |
|
196 if (a != null) { |
|
197 Component c = getContainer(); |
|
198 if (c != null) { |
|
199 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : |
|
200 a.getBounds(); |
|
201 c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); |
|
202 } |
|
203 } |
|
204 } |
|
205 |
|
206 /** |
|
207 * Change the child views. This is implemented to |
|
208 * provide the superclass behavior and invalidate the |
|
209 * grid so that rows and columns will be recalculated. |
|
210 */ |
|
211 public void replace(int offset, int length, View[] views) { |
|
212 super.replace(offset, length, views); |
|
213 invalidateGrid(); |
|
214 } |
|
215 |
|
216 /** |
|
217 * Fill in the grid locations that are placeholders |
|
218 * for multi-column, multi-row, and missing grid |
|
219 * locations. |
|
220 */ |
|
221 void updateGrid() { |
|
222 if (! gridValid) { |
|
223 // determine which views are table rows and clear out |
|
224 // grid points marked filled. |
|
225 rows.removeAllElements(); |
|
226 int n = getViewCount(); |
|
227 for (int i = 0; i < n; i++) { |
|
228 View v = getView(i); |
|
229 if (v instanceof TableRow) { |
|
230 rows.addElement(v); |
|
231 TableRow rv = (TableRow) v; |
|
232 rv.clearFilledColumns(); |
|
233 rv.setRow(i); |
|
234 } |
|
235 } |
|
236 |
|
237 int maxColumns = 0; |
|
238 int nrows = rows.size(); |
|
239 for (int row = 0; row < nrows; row++) { |
|
240 TableRow rv = getRow(row); |
|
241 int col = 0; |
|
242 for (int cell = 0; cell < rv.getViewCount(); cell++, col++) { |
|
243 View cv = rv.getView(cell); |
|
244 // advance to a free column |
|
245 for (; rv.isFilled(col); col++); |
|
246 int rowSpan = getRowsOccupied(cv); |
|
247 int colSpan = getColumnsOccupied(cv); |
|
248 if ((colSpan > 1) || (rowSpan > 1)) { |
|
249 // fill in the overflow entries for this cell |
|
250 int rowLimit = row + rowSpan; |
|
251 int colLimit = col + colSpan; |
|
252 for (int i = row; i < rowLimit; i++) { |
|
253 for (int j = col; j < colLimit; j++) { |
|
254 if (i != row || j != col) { |
|
255 addFill(i, j); |
|
256 } |
|
257 } |
|
258 } |
|
259 if (colSpan > 1) { |
|
260 col += colSpan - 1; |
|
261 } |
|
262 } |
|
263 } |
|
264 maxColumns = Math.max(maxColumns, col); |
|
265 } |
|
266 |
|
267 // setup the column layout/requirements |
|
268 columnSpans = new int[maxColumns]; |
|
269 columnOffsets = new int[maxColumns]; |
|
270 columnRequirements = new SizeRequirements[maxColumns]; |
|
271 for (int i = 0; i < maxColumns; i++) { |
|
272 columnRequirements[i] = new SizeRequirements(); |
|
273 } |
|
274 gridValid = true; |
|
275 } |
|
276 } |
|
277 |
|
278 /** |
|
279 * Mark a grid location as filled in for a cells overflow. |
|
280 */ |
|
281 void addFill(int row, int col) { |
|
282 TableRow rv = getRow(row); |
|
283 if (rv != null) { |
|
284 rv.fillColumn(col); |
|
285 } |
|
286 } |
|
287 |
|
288 /** |
|
289 * Lays out the columns to fit within the given target span. |
|
290 * Returns the results through {@code offsets} and {@code spans}. |
|
291 * |
|
292 * @param targetSpan the given span for total of all the table |
|
293 * columns |
|
294 * @param reqs the requirements desired for each column. This |
|
295 * is the column maximum of the cells minimum, preferred, and |
|
296 * maximum requested span |
|
297 * @param spans the return value of how much to allocated to |
|
298 * each column |
|
299 * @param offsets the return value of the offset from the |
|
300 * origin for each column |
|
301 */ |
|
302 protected void layoutColumns(int targetSpan, int[] offsets, int[] spans, |
|
303 SizeRequirements[] reqs) { |
|
304 // allocate using the convenience method on SizeRequirements |
|
305 SizeRequirements.calculateTiledPositions(targetSpan, null, reqs, |
|
306 offsets, spans); |
|
307 } |
|
308 |
|
309 /** |
|
310 * Perform layout for the minor axis of the box (i.e. the |
|
311 * axis orthoginal to the axis that it represents). The results |
|
312 * of the layout should be placed in the given arrays which represent |
|
313 * the allocations to the children along the minor axis. This |
|
314 * is called by the superclass whenever the layout needs to be |
|
315 * updated along the minor axis. |
|
316 * <p> |
|
317 * This is implemented to call the |
|
318 * <a href="#layoutColumns">layoutColumns</a> method, and then |
|
319 * forward to the superclass to actually carry out the layout |
|
320 * of the tables rows. |
|
321 * |
|
322 * @param targetSpan the total span given to the view, which |
|
323 * whould be used to layout the children. |
|
324 * @param axis the axis being layed out. |
|
325 * @param offsets the offsets from the origin of the view for |
|
326 * each of the child views. This is a return value and is |
|
327 * filled in by the implementation of this method. |
|
328 * @param spans the span of each child view. This is a return |
|
329 * value and is filled in by the implementation of this method. |
|
330 */ |
|
331 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { |
|
332 // make grid is properly represented |
|
333 updateGrid(); |
|
334 |
|
335 // all of the row layouts are invalid, so mark them that way |
|
336 int n = getRowCount(); |
|
337 for (int i = 0; i < n; i++) { |
|
338 TableRow row = getRow(i); |
|
339 row.layoutChanged(axis); |
|
340 } |
|
341 |
|
342 // calculate column spans |
|
343 layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements); |
|
344 |
|
345 // continue normal layout |
|
346 super.layoutMinorAxis(targetSpan, axis, offsets, spans); |
|
347 } |
|
348 |
|
349 /** |
|
350 * Calculate the requirements for the minor axis. This is called by |
|
351 * the superclass whenever the requirements need to be updated (i.e. |
|
352 * a preferenceChanged was messaged through this view). |
|
353 * <p> |
|
354 * This is implemented to calculate the requirements as the sum of the |
|
355 * requirements of the columns. |
|
356 */ |
|
357 protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { |
|
358 updateGrid(); |
|
359 |
|
360 // calculate column requirements for each column |
|
361 calculateColumnRequirements(axis); |
|
362 |
|
363 |
|
364 // the requirements are the sum of the columns. |
|
365 if (r == null) { |
|
366 r = new SizeRequirements(); |
|
367 } |
|
368 long min = 0; |
|
369 long pref = 0; |
|
370 long max = 0; |
|
371 for (int i = 0; i < columnRequirements.length; i++) { |
|
372 SizeRequirements req = columnRequirements[i]; |
|
373 min += req.minimum; |
|
374 pref += req.preferred; |
|
375 max += req.maximum; |
|
376 } |
|
377 r.minimum = (int) min; |
|
378 r.preferred = (int) pref; |
|
379 r.maximum = (int) max; |
|
380 r.alignment = 0; |
|
381 return r; |
|
382 } |
|
383 |
|
384 /* |
|
385 boolean shouldTrace() { |
|
386 AttributeSet a = getElement().getAttributes(); |
|
387 Object o = a.getAttribute(HTML.Attribute.ID); |
|
388 if ((o != null) && o.equals("debug")) { |
|
389 return true; |
|
390 } |
|
391 return false; |
|
392 } |
|
393 */ |
|
394 |
|
395 /** |
|
396 * Calculate the requirements for each column. The calculation |
|
397 * is done as two passes over the table. The table cells that |
|
398 * occupy a single column are scanned first to determine the |
|
399 * maximum of minimum, preferred, and maximum spans along the |
|
400 * give axis. Table cells that span multiple columns are excluded |
|
401 * from the first pass. A second pass is made to determine if |
|
402 * the cells that span multiple columns are satisfied. If the |
|
403 * column requirements are not satisified, the needs of the |
|
404 * multi-column cell is mixed into the existing column requirements. |
|
405 * The calculation of the multi-column distribution is based upon |
|
406 * the proportions of the existing column requirements and taking |
|
407 * into consideration any constraining maximums. |
|
408 */ |
|
409 void calculateColumnRequirements(int axis) { |
|
410 // pass 1 - single column cells |
|
411 boolean hasMultiColumn = false; |
|
412 int nrows = getRowCount(); |
|
413 for (int i = 0; i < nrows; i++) { |
|
414 TableRow row = getRow(i); |
|
415 int col = 0; |
|
416 int ncells = row.getViewCount(); |
|
417 for (int cell = 0; cell < ncells; cell++, col++) { |
|
418 View cv = row.getView(cell); |
|
419 for (; row.isFilled(col); col++); // advance to a free column |
|
420 int rowSpan = getRowsOccupied(cv); |
|
421 int colSpan = getColumnsOccupied(cv); |
|
422 if (colSpan == 1) { |
|
423 checkSingleColumnCell(axis, col, cv); |
|
424 } else { |
|
425 hasMultiColumn = true; |
|
426 col += colSpan - 1; |
|
427 } |
|
428 } |
|
429 } |
|
430 |
|
431 // pass 2 - multi-column cells |
|
432 if (hasMultiColumn) { |
|
433 for (int i = 0; i < nrows; i++) { |
|
434 TableRow row = getRow(i); |
|
435 int col = 0; |
|
436 int ncells = row.getViewCount(); |
|
437 for (int cell = 0; cell < ncells; cell++, col++) { |
|
438 View cv = row.getView(cell); |
|
439 for (; row.isFilled(col); col++); // advance to a free column |
|
440 int colSpan = getColumnsOccupied(cv); |
|
441 if (colSpan > 1) { |
|
442 checkMultiColumnCell(axis, col, colSpan, cv); |
|
443 col += colSpan - 1; |
|
444 } |
|
445 } |
|
446 } |
|
447 } |
|
448 |
|
449 /* |
|
450 if (shouldTrace()) { |
|
451 System.err.println("calc:"); |
|
452 for (int i = 0; i < columnRequirements.length; i++) { |
|
453 System.err.println(" " + i + ": " + columnRequirements[i]); |
|
454 } |
|
455 } |
|
456 */ |
|
457 } |
|
458 |
|
459 /** |
|
460 * check the requirements of a table cell that spans a single column. |
|
461 */ |
|
462 void checkSingleColumnCell(int axis, int col, View v) { |
|
463 SizeRequirements req = columnRequirements[col]; |
|
464 req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum); |
|
465 req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred); |
|
466 req.maximum = Math.max((int) v.getMaximumSpan(axis), req.maximum); |
|
467 } |
|
468 |
|
469 /** |
|
470 * check the requirements of a table cell that spans multiple |
|
471 * columns. |
|
472 */ |
|
473 void checkMultiColumnCell(int axis, int col, int ncols, View v) { |
|
474 // calculate the totals |
|
475 long min = 0; |
|
476 long pref = 0; |
|
477 long max = 0; |
|
478 for (int i = 0; i < ncols; i++) { |
|
479 SizeRequirements req = columnRequirements[col + i]; |
|
480 min += req.minimum; |
|
481 pref += req.preferred; |
|
482 max += req.maximum; |
|
483 } |
|
484 |
|
485 // check if the minimum size needs adjustment. |
|
486 int cmin = (int) v.getMinimumSpan(axis); |
|
487 if (cmin > min) { |
|
488 /* |
|
489 * the columns that this cell spans need adjustment to fit |
|
490 * this table cell.... calculate the adjustments. The |
|
491 * maximum for each cell is the maximum of the existing |
|
492 * maximum or the amount needed by the cell. |
|
493 */ |
|
494 SizeRequirements[] reqs = new SizeRequirements[ncols]; |
|
495 for (int i = 0; i < ncols; i++) { |
|
496 SizeRequirements r = reqs[i] = columnRequirements[col + i]; |
|
497 r.maximum = Math.max(r.maximum, (int) v.getMaximumSpan(axis)); |
|
498 } |
|
499 int[] spans = new int[ncols]; |
|
500 int[] offsets = new int[ncols]; |
|
501 SizeRequirements.calculateTiledPositions(cmin, null, reqs, |
|
502 offsets, spans); |
|
503 // apply the adjustments |
|
504 for (int i = 0; i < ncols; i++) { |
|
505 SizeRequirements req = reqs[i]; |
|
506 req.minimum = Math.max(spans[i], req.minimum); |
|
507 req.preferred = Math.max(req.minimum, req.preferred); |
|
508 req.maximum = Math.max(req.preferred, req.maximum); |
|
509 } |
|
510 } |
|
511 |
|
512 // check if the preferred size needs adjustment. |
|
513 int cpref = (int) v.getPreferredSpan(axis); |
|
514 if (cpref > pref) { |
|
515 /* |
|
516 * the columns that this cell spans need adjustment to fit |
|
517 * this table cell.... calculate the adjustments. The |
|
518 * maximum for each cell is the maximum of the existing |
|
519 * maximum or the amount needed by the cell. |
|
520 */ |
|
521 SizeRequirements[] reqs = new SizeRequirements[ncols]; |
|
522 for (int i = 0; i < ncols; i++) { |
|
523 SizeRequirements r = reqs[i] = columnRequirements[col + i]; |
|
524 } |
|
525 int[] spans = new int[ncols]; |
|
526 int[] offsets = new int[ncols]; |
|
527 SizeRequirements.calculateTiledPositions(cpref, null, reqs, |
|
528 offsets, spans); |
|
529 // apply the adjustments |
|
530 for (int i = 0; i < ncols; i++) { |
|
531 SizeRequirements req = reqs[i]; |
|
532 req.preferred = Math.max(spans[i], req.preferred); |
|
533 req.maximum = Math.max(req.preferred, req.maximum); |
|
534 } |
|
535 } |
|
536 |
|
537 } |
|
538 |
|
539 /** |
|
540 * Fetches the child view that represents the given position in |
|
541 * the model. This is implemented to walk through the children |
|
542 * looking for a range that contains the given position. In this |
|
543 * view the children do not necessarily have a one to one mapping |
|
544 * with the child elements. |
|
545 * |
|
546 * @param pos the search position >= 0 |
|
547 * @param a the allocation to the table on entry, and the |
|
548 * allocation of the view containing the position on exit |
|
549 * @return the view representing the given position, or |
|
550 * <code>null</code> if there isn't one |
|
551 */ |
|
552 protected View getViewAtPosition(int pos, Rectangle a) { |
|
553 int n = getViewCount(); |
|
554 for (int i = 0; i < n; i++) { |
|
555 View v = getView(i); |
|
556 int p0 = v.getStartOffset(); |
|
557 int p1 = v.getEndOffset(); |
|
558 if ((pos >= p0) && (pos < p1)) { |
|
559 // it's in this view. |
|
560 if (a != null) { |
|
561 childAllocation(i, a); |
|
562 } |
|
563 return v; |
|
564 } |
|
565 } |
|
566 if (pos == getEndOffset()) { |
|
567 View v = getView(n - 1); |
|
568 if (a != null) { |
|
569 this.childAllocation(n - 1, a); |
|
570 } |
|
571 return v; |
|
572 } |
|
573 return null; |
|
574 } |
|
575 |
|
576 // ---- variables ---------------------------------------------------- |
|
577 |
|
578 int[] columnSpans; |
|
579 int[] columnOffsets; |
|
580 SizeRequirements[] columnRequirements; |
|
581 Vector rows; |
|
582 boolean gridValid; |
|
583 static final private BitSet EMPTY = new BitSet(); |
|
584 |
|
585 /** |
|
586 * View of a row in a row-centric table. |
|
587 */ |
|
588 public class TableRow extends BoxView { |
|
589 |
|
590 /** |
|
591 * Constructs a TableView for the given element. |
|
592 * |
|
593 * @param elem the element that this view is responsible for |
|
594 * @since 1.4 |
|
595 */ |
|
596 public TableRow(Element elem) { |
|
597 super(elem, View.X_AXIS); |
|
598 fillColumns = new BitSet(); |
|
599 } |
|
600 |
|
601 void clearFilledColumns() { |
|
602 fillColumns.and(EMPTY); |
|
603 } |
|
604 |
|
605 void fillColumn(int col) { |
|
606 fillColumns.set(col); |
|
607 } |
|
608 |
|
609 boolean isFilled(int col) { |
|
610 return fillColumns.get(col); |
|
611 } |
|
612 |
|
613 /** get location in the overall set of rows */ |
|
614 int getRow() { |
|
615 return row; |
|
616 } |
|
617 |
|
618 /** |
|
619 * set location in the overall set of rows, this is |
|
620 * set by the TableView.updateGrid() method. |
|
621 */ |
|
622 void setRow(int row) { |
|
623 this.row = row; |
|
624 } |
|
625 |
|
626 /** |
|
627 * The number of columns present in this row. |
|
628 */ |
|
629 int getColumnCount() { |
|
630 int nfill = 0; |
|
631 int n = fillColumns.size(); |
|
632 for (int i = 0; i < n; i++) { |
|
633 if (fillColumns.get(i)) { |
|
634 nfill ++; |
|
635 } |
|
636 } |
|
637 return getViewCount() + nfill; |
|
638 } |
|
639 |
|
640 /** |
|
641 * Change the child views. This is implemented to |
|
642 * provide the superclass behavior and invalidate the |
|
643 * grid so that rows and columns will be recalculated. |
|
644 */ |
|
645 public void replace(int offset, int length, View[] views) { |
|
646 super.replace(offset, length, views); |
|
647 invalidateGrid(); |
|
648 } |
|
649 |
|
650 /** |
|
651 * Perform layout for the major axis of the box (i.e. the |
|
652 * axis that it represents). The results of the layout should |
|
653 * be placed in the given arrays which represent the allocations |
|
654 * to the children along the major axis. |
|
655 * <p> |
|
656 * This is re-implemented to give each child the span of the column |
|
657 * width for the table, and to give cells that span multiple columns |
|
658 * the multi-column span. |
|
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 */ |
|
669 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { |
|
670 int col = 0; |
|
671 int ncells = getViewCount(); |
|
672 for (int cell = 0; cell < ncells; cell++, col++) { |
|
673 View cv = getView(cell); |
|
674 for (; isFilled(col); col++); // advance to a free column |
|
675 int colSpan = getColumnsOccupied(cv); |
|
676 spans[cell] = columnSpans[col]; |
|
677 offsets[cell] = columnOffsets[col]; |
|
678 if (colSpan > 1) { |
|
679 int n = columnSpans.length; |
|
680 for (int j = 1; j < colSpan; j++) { |
|
681 // Because the table may be only partially formed, some |
|
682 // of the columns may not yet exist. Therefore we check |
|
683 // the bounds. |
|
684 if ((col+j) < n) { |
|
685 spans[cell] += columnSpans[col+j]; |
|
686 } |
|
687 } |
|
688 col += colSpan - 1; |
|
689 } |
|
690 } |
|
691 } |
|
692 |
|
693 /** |
|
694 * Perform layout for the minor axis of the box (i.e. the |
|
695 * axis orthoginal to the axis that it represents). The results |
|
696 * of the layout should be placed in the given arrays which represent |
|
697 * the allocations to the children along the minor axis. This |
|
698 * is called by the superclass whenever the layout needs to be |
|
699 * updated along the minor axis. |
|
700 * <p> |
|
701 * This is implemented to delegate to the superclass, then adjust |
|
702 * the span for any cell that spans multiple rows. |
|
703 * |
|
704 * @param targetSpan the total span given to the view, which |
|
705 * whould be used to layout the children. |
|
706 * @param axis the axis being layed out. |
|
707 * @param offsets the offsets from the origin of the view for |
|
708 * each of the child views. This is a return value and is |
|
709 * filled in by the implementation of this method. |
|
710 * @param spans the span of each child view. This is a return |
|
711 * value and is filled in by the implementation of this method. |
|
712 */ |
|
713 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { |
|
714 super.layoutMinorAxis(targetSpan, axis, offsets, spans); |
|
715 int col = 0; |
|
716 int ncells = getViewCount(); |
|
717 for (int cell = 0; cell < ncells; cell++, col++) { |
|
718 View cv = getView(cell); |
|
719 for (; isFilled(col); col++); // advance to a free column |
|
720 int colSpan = getColumnsOccupied(cv); |
|
721 int rowSpan = getRowsOccupied(cv); |
|
722 if (rowSpan > 1) { |
|
723 for (int j = 1; j < rowSpan; j++) { |
|
724 // test bounds of each row because it may not exist |
|
725 // either because of error or because the table isn't |
|
726 // fully loaded yet. |
|
727 int row = getRow() + j; |
|
728 if (row < TableView.this.getViewCount()) { |
|
729 int span = TableView.this.getSpan(Y_AXIS, getRow()+j); |
|
730 spans[cell] += span; |
|
731 } |
|
732 } |
|
733 } |
|
734 if (colSpan > 1) { |
|
735 col += colSpan - 1; |
|
736 } |
|
737 } |
|
738 } |
|
739 |
|
740 /** |
|
741 * Determines the resizability of the view along the |
|
742 * given axis. A value of 0 or less is not resizable. |
|
743 * |
|
744 * @param axis may be either View.X_AXIS or View.Y_AXIS |
|
745 * @return the resize weight |
|
746 * @exception IllegalArgumentException for an invalid axis |
|
747 */ |
|
748 public int getResizeWeight(int axis) { |
|
749 return 1; |
|
750 } |
|
751 |
|
752 /** |
|
753 * Fetches the child view that represents the given position in |
|
754 * the model. This is implemented to walk through the children |
|
755 * looking for a range that contains the given position. In this |
|
756 * view the children do not necessarily have a one to one mapping |
|
757 * with the child elements. |
|
758 * |
|
759 * @param pos the search position >= 0 |
|
760 * @param a the allocation to the table on entry, and the |
|
761 * allocation of the view containing the position on exit |
|
762 * @return the view representing the given position, or |
|
763 * <code>null</code> if there isn't one |
|
764 */ |
|
765 protected View getViewAtPosition(int pos, Rectangle a) { |
|
766 int n = getViewCount(); |
|
767 for (int i = 0; i < n; i++) { |
|
768 View v = getView(i); |
|
769 int p0 = v.getStartOffset(); |
|
770 int p1 = v.getEndOffset(); |
|
771 if ((pos >= p0) && (pos < p1)) { |
|
772 // it's in this view. |
|
773 if (a != null) { |
|
774 childAllocation(i, a); |
|
775 } |
|
776 return v; |
|
777 } |
|
778 } |
|
779 if (pos == getEndOffset()) { |
|
780 View v = getView(n - 1); |
|
781 if (a != null) { |
|
782 this.childAllocation(n - 1, a); |
|
783 } |
|
784 return v; |
|
785 } |
|
786 return null; |
|
787 } |
|
788 |
|
789 /** columns filled by multi-column or multi-row cells */ |
|
790 BitSet fillColumns; |
|
791 /** the row within the overall grid */ |
|
792 int row; |
|
793 } |
|
794 |
|
795 /** |
|
796 * @deprecated A table cell can now be any View implementation. |
|
797 */ |
|
798 @Deprecated |
|
799 public class TableCell extends BoxView implements GridCell { |
|
800 |
|
801 /** |
|
802 * Constructs a TableCell for the given element. |
|
803 * |
|
804 * @param elem the element that this view is responsible for |
|
805 * @since 1.4 |
|
806 */ |
|
807 public TableCell(Element elem) { |
|
808 super(elem, View.Y_AXIS); |
|
809 } |
|
810 |
|
811 // --- GridCell methods ------------------------------------- |
|
812 |
|
813 /** |
|
814 * Gets the number of columns this cell spans (e.g. the |
|
815 * grid width). |
|
816 * |
|
817 * @return the number of columns |
|
818 */ |
|
819 public int getColumnCount() { |
|
820 return 1; |
|
821 } |
|
822 |
|
823 /** |
|
824 * Gets the number of rows this cell spans (that is, the |
|
825 * grid height). |
|
826 * |
|
827 * @return the number of rows |
|
828 */ |
|
829 public int getRowCount() { |
|
830 return 1; |
|
831 } |
|
832 |
|
833 |
|
834 /** |
|
835 * Sets the grid location. |
|
836 * |
|
837 * @param row the row >= 0 |
|
838 * @param col the column >= 0 |
|
839 */ |
|
840 public void setGridLocation(int row, int col) { |
|
841 this.row = row; |
|
842 this.col = col; |
|
843 } |
|
844 |
|
845 /** |
|
846 * Gets the row of the grid location |
|
847 */ |
|
848 public int getGridRow() { |
|
849 return row; |
|
850 } |
|
851 |
|
852 /** |
|
853 * Gets the column of the grid location |
|
854 */ |
|
855 public int getGridColumn() { |
|
856 return col; |
|
857 } |
|
858 |
|
859 int row; |
|
860 int col; |
|
861 } |
|
862 |
|
863 /** |
|
864 * <em> |
|
865 * THIS IS NO LONGER USED, AND WILL BE REMOVED IN THE |
|
866 * NEXT RELEASE. THE JCK SIGNATURE TEST THINKS THIS INTERFACE |
|
867 * SHOULD EXIST |
|
868 * </em> |
|
869 */ |
|
870 interface GridCell { |
|
871 |
|
872 /** |
|
873 * Sets the grid location. |
|
874 * |
|
875 * @param row the row >= 0 |
|
876 * @param col the column >= 0 |
|
877 */ |
|
878 public void setGridLocation(int row, int col); |
|
879 |
|
880 /** |
|
881 * Gets the row of the grid location |
|
882 */ |
|
883 public int getGridRow(); |
|
884 |
|
885 /** |
|
886 * Gets the column of the grid location |
|
887 */ |
|
888 public int getGridColumn(); |
|
889 |
|
890 /** |
|
891 * Gets the number of columns this cell spans (e.g. the |
|
892 * grid width). |
|
893 * |
|
894 * @return the number of columns |
|
895 */ |
|
896 public int getColumnCount(); |
|
897 |
|
898 /** |
|
899 * Gets the number of rows this cell spans (that is, the |
|
900 * grid height). |
|
901 * |
|
902 * @return the number of rows |
|
903 */ |
|
904 public int getRowCount(); |
|
905 |
|
906 } |
|
907 |
|
908 } |