001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui;
017:
018: import com.google.gwt.user.client.DOM;
019: import com.google.gwt.user.client.Element;
020:
021: /**
022: * A rectangular grid that can contain text, html, or a child
023: * {@link com.google.gwt.user.client.ui.Widget} within its cells. It must be
024: * resized explicitly to the desired number of rows and columns.
025: * <p>
026: * <img class='gallery' src='Table.png'/>
027: * </p>
028: * <p>
029: * <h3>Example</h3>
030: * {@example com.google.gwt.examples.GridExample}
031: * </p>
032: */
033: public class Grid extends HTMLTable {
034:
035: /**
036: * Native method to add rows into a table with a given number of columns.
037: *
038: * @param table the table element
039: * @param rows number of rows to add
040: * @param columns the number of columns per row
041: */
042: private static native void addRows(Element table, int rows,
043: int columns) /*-{
044: var td = $doc.createElement("td");
045: td.innerHTML = " ";
046: var row = $doc.createElement("tr");
047: for(var cellNum = 0; cellNum < columns; cellNum++) {
048: var cell = td.cloneNode(true);
049: row.appendChild(cell);
050: }
051: table.appendChild(row);
052: for(var rowNum = 1; rowNum < rows; rowNum++) {
053: table.appendChild(row.cloneNode(true));
054: }
055: }-*/;
056:
057: /**
058: * Number of columns in the current grid.
059: */
060: protected int numColumns;
061:
062: /**
063: * Number of rows in the current grid.
064: */
065: protected int numRows;
066:
067: /**
068: * Constructor for <code>Grid</code>.
069: */
070: public Grid() {
071: super ();
072: setCellFormatter(new CellFormatter());
073: setRowFormatter(new RowFormatter());
074: setColumnFormatter(new ColumnFormatter());
075: }
076:
077: /**
078: * Constructs a grid with the requested size.
079: *
080: * @param rows the number of rows
081: * @param columns the number of columns
082: * @throws IndexOutOfBoundsException
083: */
084: public Grid(int rows, int columns) {
085: this ();
086: resize(rows, columns);
087: }
088:
089: /**
090: * Replaces the contents of the specified cell with a single space.
091: *
092: * @param row the cell's row
093: * @param column the cell's column
094: * @throws IndexOutOfBoundsException
095: */
096: @Override
097: public boolean clearCell(int row, int column) {
098: Element td = getCellFormatter().getElement(row, column);
099: boolean b = super .internalClearCell(td, false);
100: DOM.setInnerHTML(td, " ");
101: return b;
102: }
103:
104: /**
105: * Return number of columns. For grid, row argument is ignored as all grids
106: * are rectangular.
107: */
108: @Override
109: public int getCellCount(int row) {
110: return numColumns;
111: }
112:
113: /**
114: * Gets the number of columns in this grid.
115: *
116: * @return the number of columns
117: */
118: public int getColumnCount() {
119: return numColumns;
120: }
121:
122: /**
123: * Return number of rows.
124: */
125: @Override
126: public int getRowCount() {
127: return numRows;
128: }
129:
130: /**
131: * Resizes the grid.
132: *
133: * @param rows the number of rows
134: * @param columns the number of columns
135: * @throws IndexOutOfBoundsException
136: */
137: public void resize(int rows, int columns) {
138: resizeColumns(columns);
139: resizeRows(rows);
140: }
141:
142: /**
143: * Resizes the grid to the specified number of columns.
144: *
145: * @param columns the number of columns
146: * @throws IndexOutOfBoundsException
147: */
148: public void resizeColumns(int columns) {
149: if (numColumns == columns) {
150: return;
151: }
152: if (columns < 0) {
153: throw new IndexOutOfBoundsException(
154: "Cannot set number of columns to " + columns);
155: }
156:
157: if (numColumns > columns) {
158: // Fewer columns. Remove extraneous cells.
159: for (int i = 0; i < numRows; i++) {
160: for (int j = numColumns - 1; j >= columns; j--) {
161: removeCell(i, j);
162: }
163: }
164: } else {
165: // More columns. add cells where necessary.
166: for (int i = 0; i < numRows; i++) {
167: for (int j = numColumns; j < columns; j++) {
168: insertCell(i, j);
169: }
170: }
171: }
172: numColumns = columns;
173: }
174:
175: /**
176: * Resizes the grid to the specified number of rows.
177: *
178: * @param rows the number of rows
179: * @throws IndexOutOfBoundsException
180: */
181: public void resizeRows(int rows) {
182: if (numRows == rows) {
183: return;
184: }
185: if (rows < 0) {
186: throw new IndexOutOfBoundsException(
187: "Cannot set number of rows to " + rows);
188: }
189: if (numRows < rows) {
190: addRows(getBodyElement(), rows - numRows, numColumns);
191: numRows = rows;
192: } else {
193: while (numRows > rows) {
194: // Fewer rows. Remove extraneous ones.
195: removeRow(--numRows);
196: }
197: }
198: }
199:
200: /**
201: * Creates a new, empty cell.
202: */
203: @Override
204: protected Element createCell() {
205: Element td = super .createCell();
206:
207: // Add a non-breaking space to the TD. This ensures that the cell is
208: // displayed.
209: DOM.setInnerHTML(td, " ");
210: return td;
211: }
212:
213: /**
214: * Checks that a cell is a valid cell in the table.
215: *
216: * @param row the cell's row
217: * @param column the cell's column
218: * @throws IndexOutOfBoundsException
219: */
220: @Override
221: protected void prepareCell(int row, int column) {
222: // Ensure that the indices are not negative.
223: prepareRow(row);
224: if (column < 0) {
225: throw new IndexOutOfBoundsException(
226: "Cannot access a column with a negative index: "
227: + column);
228: }
229:
230: if (column >= numColumns) {
231: throw new IndexOutOfBoundsException("Column index: "
232: + column + ", Column size: " + numColumns);
233: }
234: }
235:
236: /**
237: * Checks that the column index is valid.
238: *
239: * @param column The column index to be checked
240: * @throws IndexOutOfBoundsException if the column is negative
241: */
242: @Override
243: protected void prepareColumn(int column) {
244: // Ensure that the indices are not negative.
245: if (column < 0) {
246: throw new IndexOutOfBoundsException(
247: "Cannot access a column with a negative index: "
248: + column);
249: }
250:
251: /**
252: * Grid does not lazily create cells, so simply ensure that the requested
253: * column and column are valid
254: */
255: if (column >= numColumns) {
256: throw new IndexOutOfBoundsException("Column index: "
257: + column + ", Column size: " + numColumns);
258: }
259: }
260:
261: /**
262: * Checks that the row index is valid.
263: *
264: * @param row The row index to be checked
265: * @throws IndexOutOfBoundsException if the row is negative
266: */
267: @Override
268: protected void prepareRow(int row) {
269: // Ensure that the indices are not negative.
270: if (row < 0) {
271: throw new IndexOutOfBoundsException(
272: "Cannot access a row with a negative index: " + row);
273: }
274:
275: /**
276: * Grid does not lazily create cells, so simply ensure that the requested
277: * row and column are valid
278: */
279: if (row >= numRows) {
280: throw new IndexOutOfBoundsException("Row index: " + row
281: + ", Row size: " + numRows);
282: }
283: }
284: }
|