Frames | No Frames |
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 <= 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: }