Source for javax.swing.text.TableView

   1: /* TableView.java -- A view impl for tables inside styled text
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.text;
  40: 
  41: import java.awt.Rectangle;
  42: import java.awt.Shape;
  43: 
  44: import javax.swing.SizeRequirements;
  45: import javax.swing.event.DocumentEvent;
  46: 
  47: /**
  48:  * A {@link View} implementation for rendering tables inside styled text.
  49:  * Tables are rendered as vertical boxes (see {@link BoxView}). These boxes
  50:  * have a number of child views, which are the rows of the table. These are
  51:  * horizontal boxes containing the actuall cells of the table. These cells
  52:  * can be arbitrary view implementations and are fetched via the
  53:  * {@link ViewFactory} returned by {@link View#getViewFactory}.
  54:  * 
  55:  * @author Roman Kennke (kennke@aicas.com)
  56:  */
  57: public abstract class TableView
  58:   extends BoxView
  59: {
  60: 
  61:   /**
  62:    * A view implementation that renders a row of a <code>TableView</code>.
  63:    * This is implemented as a horizontal box that contains the actual cells
  64:    * of the table.
  65:    *
  66:    * @author Roman Kennke (kennke@aicas.com)
  67:    */
  68:   public class TableRow
  69:     extends BoxView
  70:   {
  71:     /**
  72:      * Creates a new instance of <code>TableRow</code>.
  73:      *
  74:      * @param el the element for which to create a row view
  75:      */
  76:     public TableRow(Element el)
  77:     {
  78:       super(el, X_AXIS);
  79:     }
  80: 
  81:     /**
  82:      * Replaces some child views with a new set of child views. This is
  83:      * implemented to call the superclass behaviour and invalidates the row
  84:      * grid so that rows and columns will be recalculated.
  85:      *
  86:      * @param offset the start offset at which to replace views
  87:      * @param length the number of views to remove
  88:      * @param views the new set of views
  89:      */
  90:     public void replace(int offset, int length, View[] views)
  91:     {
  92:       super.replace(offset, length, views);
  93:       int viewCount = getViewCount();
  94:       if (columnRequirements == null
  95:           || viewCount > columnRequirements.length)
  96:         {
  97:           columnRequirements = new SizeRequirements[viewCount];
  98:           for (int i = 0; i < columnRequirements.length; i++)
  99:             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 &lt;= 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: }