| /* 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)); |
| } |
| } |
| } |
| } |