| /* TableView.java -- A view impl for tables inside styled text | |
| Copyright (C) 2006 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package javax.swing.text; | |
| import java.awt.Rectangle; | |
| import java.awt.Shape; | |
| import javax.swing.SizeRequirements; | |
| import javax.swing.event.DocumentEvent; | |
| /** | |
| * A {@link View} implementation for rendering tables inside styled text. | |
| * Tables are rendered as vertical boxes (see {@link BoxView}). These boxes | |
| * have a number of child views, which are the rows of the table. These are | |
| * horizontal boxes containing the actuall cells of the table. These cells | |
| * can be arbitrary view implementations and are fetched via the | |
| * {@link ViewFactory} returned by {@link View#getViewFactory}. | |
| * | |
| * @author Roman Kennke (kennke@aicas.com) | |
| */ | |
| public abstract class TableView | |
| extends BoxView | |
| { | |
| /** | |
| * A view implementation that renders a row of a <code>TableView</code>. | |
| * This is implemented as a horizontal box that contains the actual cells | |
| * of the table. | |
| * | |
| * @author Roman Kennke (kennke@aicas.com) | |
| */ | |
| public class TableRow | |
| extends BoxView | |
| { | |
| /** | |
| * Creates a new instance of <code>TableRow</code>. | |
| * | |
| * @param el the element for which to create a row view | |
| */ | |
| public TableRow(Element el) | |
| { | |
| super(el, X_AXIS); | |
| } | |
| /** | |
| * Replaces some child views with a new set of child views. This is | |
| * implemented to call the superclass behaviour and invalidates the row | |
| * grid so that rows and columns will be recalculated. | |
| * | |
| * @param offset the start offset at which to replace views | |
| * @param length the number of views to remove | |
| * @param views the new set of views | |
| */ | |
| public void replace(int offset, int length, View[] views) | |
| { | |
| super.replace(offset, length, views); | |
| int viewCount = getViewCount(); | |
| if (columnRequirements == null | |
| || viewCount > columnRequirements.length) | |
| { | |
| columnRequirements = new SizeRequirements[viewCount]; | |
| for (int i = 0; i < columnRequirements.length; i++) | |
| columnRequirements[i] = new SizeRequirements(); | |
| } | |
| if (columnOffsets == null || columnOffsets.length < viewCount) | |
| columnOffsets = new int[viewCount]; | |
| if (columnSpans == null || columnSpans.length < viewCount) | |
| columnSpans = new int[viewCount]; | |
| layoutChanged(X_AXIS); | |
| } | |
| /** | |
| * Lays out the box's child views along the major axis. This is | |
| * reimplemented so that the child views all have the width of their | |
| * column. | |
| * | |
| * @param targetSpan the total span of the view | |
| * @param axis the axis that is laid out | |
| * @param offsets an array that holds the offsets of the child views after | |
| * this method returned | |
| * @param spans an array that holds the spans of the child views after this | |
| * method returned | |
| */ | |
| protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, | |
| int[] spans) | |
| { | |
| // Some sanity checks. If these preconditions are not met, then the | |
| // following code will not work. Also, there must be something | |
| // seriously wrong then. | |
| assert(offsets.length == columnOffsets.length); | |
| assert(spans.length == columnSpans.length); | |
| assert(offsets.length == spans.length); | |
| for (int i = 0; i < offsets.length; ++i) | |
| { | |
| offsets[i] = columnOffsets[i]; | |
| spans[i] = columnSpans[i]; | |
| } | |
| } | |
| /** | |
| * Lays out the box's child views along the minor axis (the orthogonal axis | |
| * to the major axis). This is reimplemented to call the super behaviour | |
| * and then adjust the span of the child views that span multiple rows. | |
| * | |
| * @param targetSpan the total span of the view | |
| * @param axis the axis that is laid out | |
| * @param offsets an array that holds the offsets of the child views after | |
| * this method returned | |
| * @param spans an array that holds the spans of the child views after this | |
| * method returned | |
| */ | |
| protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, | |
| int[] spans) | |
| { | |
| // FIXME: Figure out how to fetch the row heights from the TableView's | |
| // element. | |
| super.layoutMinorAxis(targetSpan, axis, offsets, spans); | |
| } | |
| /** | |
| * Determines the resizeability of this view along the specified axis. | |
| * | |
| * @param axis the axis of which to fetch the resizability | |
| * | |
| * @return the resize weight or <= 0 if this view is not resizable | |
| * | |
| * @throws IllegalArgumentException when an illegal axis is specified | |
| */ | |
| public int getResizeWeight(int axis) | |
| { | |
| // TODO: Figure out if this is ok. I would think so, but better test | |
| // this. | |
| return 0; | |
| } | |
| /** | |
| * Returns the child view that represents the specified position in the | |
| * model. This is reimplemented because in this view we do not necessarily | |
| * have a one to one mapping of child elements to child views. | |
| * | |
| * @param pos the model position for which to query the view | |
| * @param a the allocation of this view | |
| * | |
| * @return the view that corresponds to the specified model position or | |
| * <code>null</code> if there is none | |
| */ | |
| protected View getViewAtPosition(int pos, Rectangle a) | |
| { | |
| // FIXME: Do not call super here. Instead walk through the child views | |
| // and look for a range that contains the given position. | |
| return super.getViewAtPosition(pos, a); | |
| } | |
| } | |
| /** | |
| * This class is deprecated and not used anymore. Table cells are | |
| * rendered by an arbitrary <code>View</code> implementation. | |
| * | |
| * @author Roman Kennke (kennke@aicas.com) | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary <code>View</code> | |
| * implementation. | |
| */ | |
| public class TableCell | |
| extends BoxView | |
| { | |
| /** | |
| * The row number of this cell. | |
| */ | |
| private int row; | |
| /** | |
| * The column number of this cell. | |
| */ | |
| private int column; | |
| /** | |
| * Creates a new instance. | |
| * | |
| * @param el the element | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public TableCell(Element el) | |
| { | |
| super(el, X_AXIS); | |
| } | |
| /** | |
| * Returns the number of columns that this cell spans. | |
| * | |
| * @return the number of columns that this cell spans | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public int getColumnCount() | |
| { | |
| // TODO: Figure out if this is right. However, this is not so important | |
| // since this class isn't used anyway (except maybe be application code | |
| // that still uses this deprecated class). | |
| return 1; | |
| } | |
| /** | |
| * Returns the number of rows that this cell spans. | |
| * | |
| * @return the number of rows that this cell spans | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public int getRowCount() | |
| { | |
| // TODO: Figure out if this is right. However, this is not so important | |
| // since this class isn't used anyway (except maybe be application code | |
| // that still uses this deprecated class). | |
| return 1; | |
| } | |
| /** | |
| * Sets the grid location of this table cell. | |
| * | |
| * @param r the row of this cell | |
| * @param c the column of this cell | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public void setGridLocation(int r, int c) | |
| { | |
| row = r; | |
| column = c; | |
| } | |
| /** | |
| * Returns the row number of this cell. | |
| * | |
| * @return the row number of this cell | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public int getGridRow() | |
| { | |
| return row; | |
| } | |
| /** | |
| * Returns the column number of this cell. | |
| * | |
| * @return the column number of this cell | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| public int getGridColumn() | |
| { | |
| return column; | |
| } | |
| } | |
| /** | |
| * The offsets of the columns of this table. Package private to avoid | |
| * synthetic accessor methods. | |
| */ | |
| int[] columnOffsets; | |
| /** | |
| * The spans of the columns of this table. Package private to avoid | |
| * synthetic accessor methods. | |
| */ | |
| int[] columnSpans; | |
| /** | |
| * The size requirements of the columns. | |
| */ | |
| SizeRequirements[] columnRequirements = new SizeRequirements[0]; | |
| /** | |
| * Creates a new instance of <code>TableView</code>. | |
| * | |
| * @param el the element for which to create a table view | |
| */ | |
| public TableView(Element el) | |
| { | |
| super(el, Y_AXIS); | |
| } | |
| /** | |
| * Replaces a number of child views with a set of new child views. This is | |
| * implemented to call the superclass behaviour and invalidate the layout. | |
| * | |
| * @param offset the offset at which to replace child views | |
| * @param length the number of child views to remove | |
| * @param views the new set of views | |
| */ | |
| public void replace(int offset, int length, View[] views) | |
| { | |
| super.replace(offset, length, views); | |
| layoutChanged(Y_AXIS); | |
| } | |
| /** | |
| * Creates a view for a table row. | |
| * | |
| * @param el the element that represents the table row | |
| * | |
| * @return a view for rendering the table row | |
| */ | |
| protected TableRow createTableRow(Element el) | |
| { | |
| return new TableRow(el); | |
| } | |
| /** | |
| * Creates a view for a table cell. This method is deprecated and not used | |
| * anymore. | |
| * | |
| * @param el the element that represents the table cell | |
| * | |
| * @return a view for rendering the table cell | |
| * | |
| * @deprecated Table cells are now rendered by an arbitrary | |
| * <code>View</code> implementation. | |
| */ | |
| protected TableCell createTableCell(Element el) | |
| { | |
| return new TableCell(el); | |
| } | |
| protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, | |
| Shape a, ViewFactory vf) | |
| { | |
| // TODO: Figure out what to do here. | |
| } | |
| /** | |
| * Lays out the columns to fit within the specified target span. | |
| * | |
| * @param targetSpan the total span for the columns | |
| * @param offsets an array that holds the offsets of the columns when this | |
| * method returns | |
| * @param spans an array that holds the spans of the columns when this method | |
| * returns | |
| * @param reqs the size requirements for each column | |
| */ | |
| protected void layoutColumns(int targetSpan, int[] offsets, int spans[], | |
| SizeRequirements[] reqs) | |
| { | |
| updateColumnRequirements(); | |
| SizeRequirements r = calculateMinorAxisRequirements(X_AXIS, null); | |
| SizeRequirements.calculateTiledPositions(targetSpan, r, columnRequirements, | |
| offsets, spans); | |
| } | |
| /** | |
| * Lays out the child views along the minor axis of the table (that is the | |
| * horizontal axis). This is implemented to call {@link #layoutColumns} to | |
| * layout the column layout of this table, and then forward to the superclass | |
| * to actually lay out the rows. | |
| * | |
| * @param targetSpan the available span along the minor (horizontal) axis | |
| * @param axis the axis | |
| * @param offsets an array that holds the offsets of the columns when this | |
| * method returns | |
| * @param spans an array that holds the spans of the columns when this method | |
| * returns | |
| */ | |
| protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, | |
| int[] spans) | |
| { | |
| // TODO: Prepare size requirements for the columns. | |
| layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements); | |
| super.layoutMinorAxis(targetSpan, axis, offsets, spans); | |
| } | |
| /** | |
| * Calculates the requirements of this view for the minor (== horizontal) | |
| * axis. | |
| * | |
| * This is reimplemented to calculate the requirements as the sum of the | |
| * size requirements of the columns. | |
| * | |
| * @param axis the axis | |
| * @param req the size requirements object to use, if <code>null</code> a new | |
| * one will be created | |
| */ | |
| protected SizeRequirements calculateMinorAxisRequirements(int axis, | |
| SizeRequirements req) | |
| { | |
| // TODO: Maybe prepare columnRequirements. | |
| SizeRequirements res = req; | |
| if (res == null) | |
| res = new SizeRequirements(); | |
| else | |
| { | |
| res.alignment = 0.5f; | |
| res.maximum = 0; | |
| res.minimum = 0; | |
| res.preferred = 0; | |
| } | |
| for (int i = 0; i < columnRequirements.length; ++i) | |
| { | |
| res.minimum += columnRequirements[i].minimum; | |
| res.preferred += columnRequirements[i].preferred; | |
| res.maximum += columnRequirements[i].maximum; | |
| // TODO: Do we have to handle alignment somehow? | |
| } | |
| return res; | |
| } | |
| /** | |
| * Returns the child view that represents the specified position in the | |
| * model. This is reimplemented because in this view we do not necessarily | |
| * have a one to one mapping of child elements to child views. | |
| * | |
| * @param pos the model position for which to query the view | |
| * @param a the allocation of this view | |
| * | |
| * @return the view that corresponds to the specified model position or | |
| * <code>null</code> if there is none | |
| */ | |
| protected View getViewAtPosition(int pos, Rectangle a) | |
| { | |
| // FIXME: Do not call super here. Instead walk through the child views | |
| // and look for a range that contains the given position. | |
| return super.getViewAtPosition(pos, a); | |
| } | |
| /** | |
| * Updates the column requirements. | |
| */ | |
| private void updateColumnRequirements() | |
| { | |
| int rowCount = getViewCount(); | |
| for (int r = 0; r < rowCount; ++r) | |
| { | |
| TableRow row = (TableRow) getView(r); | |
| int columnCount = row.getViewCount(); | |
| for (int c = 0; c < columnCount; ++c) | |
| { | |
| View cell = row.getView(c); | |
| SizeRequirements cr = columnRequirements[c]; | |
| cr.minimum = Math.max(cr.minimum, (int) cell.getMinimumSpan(X_AXIS)); | |
| cr.preferred = Math.max(cr.preferred, | |
| (int) cell.getPreferredSpan(X_AXIS)); | |
| cr.maximum = Math.max(cr.maximum, (int) cell.getMaximumSpan(X_AXIS)); | |
| } | |
| } | |
| } | |
| } |