001 /* TableView.java -- A view impl for tables inside styled text
002 Copyright (C) 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.swing.text;
040
041 import java.awt.Rectangle;
042 import java.awt.Shape;
043
044 import javax.swing.SizeRequirements;
045 import javax.swing.event.DocumentEvent;
046
047 /**
048 * A {@link View} implementation for rendering tables inside styled text.
049 * Tables are rendered as vertical boxes (see {@link BoxView}). These boxes
050 * have a number of child views, which are the rows of the table. These are
051 * horizontal boxes containing the actuall cells of the table. These cells
052 * can be arbitrary view implementations and are fetched via the
053 * {@link ViewFactory} returned by {@link View#getViewFactory}.
054 *
055 * @author Roman Kennke (kennke@aicas.com)
056 */
057 public abstract class TableView
058 extends BoxView
059 {
060
061 /**
062 * A view implementation that renders a row of a <code>TableView</code>.
063 * This is implemented as a horizontal box that contains the actual cells
064 * of the table.
065 *
066 * @author Roman Kennke (kennke@aicas.com)
067 */
068 public class TableRow
069 extends BoxView
070 {
071 /**
072 * Creates a new instance of <code>TableRow</code>.
073 *
074 * @param el the element for which to create a row view
075 */
076 public TableRow(Element el)
077 {
078 super(el, X_AXIS);
079 }
080
081 /**
082 * Replaces some child views with a new set of child views. This is
083 * implemented to call the superclass behaviour and invalidates the row
084 * grid so that rows and columns will be recalculated.
085 *
086 * @param offset the start offset at which to replace views
087 * @param length the number of views to remove
088 * @param views the new set of views
089 */
090 public void replace(int offset, int length, View[] views)
091 {
092 super.replace(offset, length, views);
093 int viewCount = getViewCount();
094 if (columnRequirements == null
095 || viewCount > columnRequirements.length)
096 {
097 columnRequirements = new SizeRequirements[viewCount];
098 for (int i = 0; i < columnRequirements.length; i++)
099 columnRequirements[i] = new SizeRequirements();
100 }
101 if (columnOffsets == null || columnOffsets.length < viewCount)
102 columnOffsets = new int[viewCount];
103 if (columnSpans == null || columnSpans.length < viewCount)
104 columnSpans = new int[viewCount];
105 layoutChanged(X_AXIS);
106 }
107
108 /**
109 * Lays out the box's child views along the major axis. This is
110 * reimplemented so that the child views all have the width of their
111 * column.
112 *
113 * @param targetSpan the total span of the view
114 * @param axis the axis that is laid out
115 * @param offsets an array that holds the offsets of the child views after
116 * this method returned
117 * @param spans an array that holds the spans of the child views after this
118 * method returned
119 */
120 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
121 int[] spans)
122 {
123 // Some sanity checks. If these preconditions are not met, then the
124 // following code will not work. Also, there must be something
125 // seriously wrong then.
126 assert(offsets.length == columnOffsets.length);
127 assert(spans.length == columnSpans.length);
128 assert(offsets.length == spans.length);
129 for (int i = 0; i < offsets.length; ++i)
130 {
131 offsets[i] = columnOffsets[i];
132 spans[i] = columnSpans[i];
133 }
134 }
135
136 /**
137 * Lays out the box's child views along the minor axis (the orthogonal axis
138 * to the major axis). This is reimplemented to call the super behaviour
139 * and then adjust the span of the child views that span multiple rows.
140 *
141 * @param targetSpan the total span of the view
142 * @param axis the axis that is laid out
143 * @param offsets an array that holds the offsets of the child views after
144 * this method returned
145 * @param spans an array that holds the spans of the child views after this
146 * method returned
147 */
148 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
149 int[] spans)
150 {
151 // FIXME: Figure out how to fetch the row heights from the TableView's
152 // element.
153 super.layoutMinorAxis(targetSpan, axis, offsets, spans);
154 }
155
156 /**
157 * Determines the resizeability of this view along the specified axis.
158 *
159 * @param axis the axis of which to fetch the resizability
160 *
161 * @return the resize weight or <= 0 if this view is not resizable
162 *
163 * @throws IllegalArgumentException when an illegal axis is specified
164 */
165 public int getResizeWeight(int axis)
166 {
167 // TODO: Figure out if this is ok. I would think so, but better test
168 // this.
169 return 0;
170 }
171
172 /**
173 * Returns the child view that represents the specified position in the
174 * model. This is reimplemented because in this view we do not necessarily
175 * have a one to one mapping of child elements to child views.
176 *
177 * @param pos the model position for which to query the view
178 * @param a the allocation of this view
179 *
180 * @return the view that corresponds to the specified model position or
181 * <code>null</code> if there is none
182 */
183 protected View getViewAtPosition(int pos, Rectangle a)
184 {
185 // FIXME: Do not call super here. Instead walk through the child views
186 // and look for a range that contains the given position.
187 return super.getViewAtPosition(pos, a);
188 }
189 }
190
191 /**
192 * This class is deprecated and not used anymore. Table cells are
193 * rendered by an arbitrary <code>View</code> implementation.
194 *
195 * @author Roman Kennke (kennke@aicas.com)
196 *
197 * @deprecated Table cells are now rendered by an arbitrary <code>View</code>
198 * implementation.
199 */
200 public class TableCell
201 extends BoxView
202 {
203
204 /**
205 * The row number of this cell.
206 */
207 private int row;
208
209 /**
210 * The column number of this cell.
211 */
212 private int column;
213
214 /**
215 * Creates a new instance.
216 *
217 * @param el the element
218 *
219 * @deprecated Table cells are now rendered by an arbitrary
220 * <code>View</code> implementation.
221 */
222 public TableCell(Element el)
223 {
224 super(el, X_AXIS);
225 }
226
227 /**
228 * Returns the number of columns that this cell spans.
229 *
230 * @return the number of columns that this cell spans
231 *
232 * @deprecated Table cells are now rendered by an arbitrary
233 * <code>View</code> implementation.
234 */
235 public int getColumnCount()
236 {
237 // TODO: Figure out if this is right. However, this is not so important
238 // since this class isn't used anyway (except maybe be application code
239 // that still uses this deprecated class).
240 return 1;
241 }
242
243 /**
244 * Returns the number of rows that this cell spans.
245 *
246 * @return the number of rows that this cell spans
247 *
248 * @deprecated Table cells are now rendered by an arbitrary
249 * <code>View</code> implementation.
250 */
251 public int getRowCount()
252 {
253 // TODO: Figure out if this is right. However, this is not so important
254 // since this class isn't used anyway (except maybe be application code
255 // that still uses this deprecated class).
256 return 1;
257 }
258
259 /**
260 * Sets the grid location of this table cell.
261 *
262 * @param r the row of this cell
263 * @param c the column of this cell
264 *
265 * @deprecated Table cells are now rendered by an arbitrary
266 * <code>View</code> implementation.
267 */
268 public void setGridLocation(int r, int c)
269 {
270 row = r;
271 column = c;
272 }
273
274 /**
275 * Returns the row number of this cell.
276 *
277 * @return the row number of this cell
278 *
279 * @deprecated Table cells are now rendered by an arbitrary
280 * <code>View</code> implementation.
281 */
282 public int getGridRow()
283 {
284 return row;
285 }
286
287 /**
288 * Returns the column number of this cell.
289 *
290 * @return the column number of this cell
291 *
292 * @deprecated Table cells are now rendered by an arbitrary
293 * <code>View</code> implementation.
294 */
295 public int getGridColumn()
296 {
297 return column;
298 }
299 }
300
301 /**
302 * The offsets of the columns of this table. Package private to avoid
303 * synthetic accessor methods.
304 */
305 int[] columnOffsets;
306
307 /**
308 * The spans of the columns of this table. Package private to avoid
309 * synthetic accessor methods.
310 */
311 int[] columnSpans;
312
313 /**
314 * The size requirements of the columns.
315 */
316 SizeRequirements[] columnRequirements = new SizeRequirements[0];
317
318 /**
319 * Creates a new instance of <code>TableView</code>.
320 *
321 * @param el the element for which to create a table view
322 */
323 public TableView(Element el)
324 {
325 super(el, Y_AXIS);
326 }
327
328 /**
329 * Replaces a number of child views with a set of new child views. This is
330 * implemented to call the superclass behaviour and invalidate the layout.
331 *
332 * @param offset the offset at which to replace child views
333 * @param length the number of child views to remove
334 * @param views the new set of views
335 */
336 public void replace(int offset, int length, View[] views)
337 {
338 super.replace(offset, length, views);
339 layoutChanged(Y_AXIS);
340 }
341
342 /**
343 * Creates a view for a table row.
344 *
345 * @param el the element that represents the table row
346 *
347 * @return a view for rendering the table row
348 */
349 protected TableRow createTableRow(Element el)
350 {
351 return new TableRow(el);
352 }
353
354 /**
355 * Creates a view for a table cell. This method is deprecated and not used
356 * anymore.
357 *
358 * @param el the element that represents the table cell
359 *
360 * @return a view for rendering the table cell
361 *
362 * @deprecated Table cells are now rendered by an arbitrary
363 * <code>View</code> implementation.
364 */
365 protected TableCell createTableCell(Element el)
366 {
367 return new TableCell(el);
368 }
369
370 protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e,
371 Shape a, ViewFactory vf)
372 {
373 // TODO: Figure out what to do here.
374 }
375
376 /**
377 * Lays out the columns to fit within the specified target span.
378 *
379 * @param targetSpan the total span for the columns
380 * @param offsets an array that holds the offsets of the columns when this
381 * method returns
382 * @param spans an array that holds the spans of the columns when this method
383 * returns
384 * @param reqs the size requirements for each column
385 */
386 protected void layoutColumns(int targetSpan, int[] offsets, int spans[],
387 SizeRequirements[] reqs)
388 {
389 updateColumnRequirements();
390 SizeRequirements r = calculateMinorAxisRequirements(X_AXIS, null);
391 SizeRequirements.calculateTiledPositions(targetSpan, r, columnRequirements,
392 offsets, spans);
393 }
394
395 /**
396 * Lays out the child views along the minor axis of the table (that is the
397 * horizontal axis). This is implemented to call {@link #layoutColumns} to
398 * layout the column layout of this table, and then forward to the superclass
399 * to actually lay out the rows.
400 *
401 * @param targetSpan the available span along the minor (horizontal) axis
402 * @param axis the axis
403 * @param offsets an array that holds the offsets of the columns when this
404 * method returns
405 * @param spans an array that holds the spans of the columns when this method
406 * returns
407 */
408 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
409 int[] spans)
410 {
411 // TODO: Prepare size requirements for the columns.
412 layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
413 super.layoutMinorAxis(targetSpan, axis, offsets, spans);
414 }
415
416 /**
417 * Calculates the requirements of this view for the minor (== horizontal)
418 * axis.
419 *
420 * This is reimplemented to calculate the requirements as the sum of the
421 * size requirements of the columns.
422 *
423 * @param axis the axis
424 * @param req the size requirements object to use, if <code>null</code> a new
425 * one will be created
426 */
427 protected SizeRequirements calculateMinorAxisRequirements(int axis,
428 SizeRequirements req)
429 {
430 // TODO: Maybe prepare columnRequirements.
431 SizeRequirements res = req;
432 if (res == null)
433 res = new SizeRequirements();
434 else
435 {
436 res.alignment = 0.5f;
437 res.maximum = 0;
438 res.minimum = 0;
439 res.preferred = 0;
440 }
441
442 for (int i = 0; i < columnRequirements.length; ++i)
443 {
444 res.minimum += columnRequirements[i].minimum;
445 res.preferred += columnRequirements[i].preferred;
446 res.maximum += columnRequirements[i].maximum;
447 // TODO: Do we have to handle alignment somehow?
448 }
449 return res;
450 }
451
452 /**
453 * Returns the child view that represents the specified position in the
454 * model. This is reimplemented because in this view we do not necessarily
455 * have a one to one mapping of child elements to child views.
456 *
457 * @param pos the model position for which to query the view
458 * @param a the allocation of this view
459 *
460 * @return the view that corresponds to the specified model position or
461 * <code>null</code> if there is none
462 */
463 protected View getViewAtPosition(int pos, Rectangle a)
464 {
465 // FIXME: Do not call super here. Instead walk through the child views
466 // and look for a range that contains the given position.
467 return super.getViewAtPosition(pos, a);
468 }
469
470 /**
471 * Updates the column requirements.
472 */
473 private void updateColumnRequirements()
474 {
475 int rowCount = getViewCount();
476 for (int r = 0; r < rowCount; ++r)
477 {
478 TableRow row = (TableRow) getView(r);
479 int columnCount = row.getViewCount();
480 for (int c = 0; c < columnCount; ++c)
481 {
482 View cell = row.getView(c);
483 SizeRequirements cr = columnRequirements[c];
484 cr.minimum = Math.max(cr.minimum, (int) cell.getMinimumSpan(X_AXIS));
485 cr.preferred = Math.max(cr.preferred,
486 (int) cell.getPreferredSpan(X_AXIS));
487 cr.maximum = Math.max(cr.maximum, (int) cell.getMaximumSpan(X_AXIS));
488 }
489 }
490 }
491 }