You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Grid.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. /*
  2. * Copyright 2000-2013 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui.grid;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import com.google.gwt.core.shared.GWT;
  21. import com.google.gwt.user.client.ui.Composite;
  22. import com.vaadin.client.data.DataChangeHandler;
  23. import com.vaadin.client.data.DataSource;
  24. import com.vaadin.shared.util.SharedUtil;
  25. /**
  26. * A data grid view that supports columns and lazy loading of data rows from a
  27. * data source.
  28. *
  29. * <h3>Columns</h3>
  30. * <p>
  31. * The {@link GridColumn} class defines the renderer used to render a cell in
  32. * the grid. Implement {@link GridColumn#getValue(Object)} to retrieve the cell
  33. * value from the row object and return the cell renderer to render that cell.
  34. * </p>
  35. * <p>
  36. * {@link GridColumn}s contain other properties like the width of the column and
  37. * the visiblity of the column. If you want to change a column's properties
  38. * after it has been added to the grid you can get a column object for a
  39. * specific column index using {@link Grid#getColumn(int)}.
  40. * </p>
  41. * <p>
  42. *
  43. * TODO Explain about headers/footers once the multiple header/footer api has
  44. * been implemented
  45. *
  46. * <h3>Data sources</h3>
  47. * <p>
  48. * TODO Explain about what a data source is and how it should be implemented.
  49. * </p>
  50. *
  51. * @since 7.2
  52. * @author Vaadin Ltd
  53. */
  54. public class Grid<T> extends Composite {
  55. /**
  56. * Escalator used internally by grid to render the rows
  57. */
  58. private Escalator escalator = GWT.create(Escalator.class);
  59. /**
  60. * List of columns in the grid. Order defines the visible order.
  61. */
  62. private final List<GridColumn<T>> columns = new ArrayList<GridColumn<T>>();
  63. private DataSource<T> dataSource;
  64. /**
  65. * The column groups rows added to the grid
  66. */
  67. private final List<ColumnGroupRow> columnGroupRows = new ArrayList<ColumnGroupRow>();
  68. /**
  69. * Are the headers for the columns visible
  70. */
  71. private boolean columnHeadersVisible = false;
  72. /**
  73. * Are the footers for the columns visible
  74. */
  75. private boolean columnFootersVisible = false;
  76. /**
  77. * Base class for grid columns internally used by the Grid. The user should
  78. * use {@link GridColumn} when creating new columns.
  79. *
  80. * @param <T>
  81. * the row type
  82. */
  83. public static abstract class AbstractGridColumn<T> {
  84. /**
  85. * The grid the column is associated with
  86. */
  87. private Grid<T> grid;
  88. /**
  89. * Should the column be visible in the grid
  90. */
  91. private boolean visible;
  92. /**
  93. * The text displayed in the header of the column
  94. */
  95. private String header;
  96. /**
  97. * Text displayed in the column footer
  98. */
  99. private String footer;
  100. /**
  101. * Internally used by the grid to set itself
  102. *
  103. * @param grid
  104. */
  105. private void setGrid(Grid<T> grid) {
  106. if (this.grid != null && grid != null) {
  107. // Trying to replace grid
  108. throw new IllegalStateException(
  109. "Column already is attached to grid. Remove the column first from the grid and then add it.");
  110. }
  111. this.grid = grid;
  112. }
  113. /**
  114. * Gets text in the header of the column. By default the header caption
  115. * is empty.
  116. *
  117. * @return the text displayed in the column caption
  118. */
  119. public String getHeaderCaption() {
  120. return header;
  121. }
  122. /**
  123. * Sets the text in the header of the column.
  124. *
  125. * @param caption
  126. * the text displayed in the column header
  127. */
  128. public void setHeaderCaption(String caption) {
  129. if (SharedUtil.equals(caption, header)) {
  130. return;
  131. }
  132. header = caption;
  133. if (grid != null) {
  134. grid.refreshHeader();
  135. }
  136. }
  137. /**
  138. * Gets text in the footer of the column. By default the footer caption
  139. * is empty.
  140. *
  141. * @return The text displayed in the footer of the column
  142. */
  143. public String getFooterCaption() {
  144. return footer;
  145. }
  146. /**
  147. * Sets text in the footer of the column.
  148. *
  149. * @param caption
  150. * the text displayed in the footer of the column
  151. */
  152. public void setFooterCaption(String caption) {
  153. if (SharedUtil.equals(caption, footer)) {
  154. return;
  155. }
  156. footer = caption;
  157. if (grid != null) {
  158. grid.refreshFooter();
  159. }
  160. }
  161. /**
  162. * Is the column visible. By default all columns are visible.
  163. *
  164. * @return <code>true</code> if the column is visible
  165. */
  166. public boolean isVisible() {
  167. return visible;
  168. }
  169. /**
  170. * Sets a column as visible in the grid.
  171. *
  172. * @param visible
  173. * <code>true</code> if the column should be displayed in the
  174. * grid
  175. */
  176. public void setVisible(boolean visible) {
  177. if (this.visible == visible) {
  178. return;
  179. }
  180. // Remove column
  181. if (grid != null) {
  182. int index = findIndexOfColumn();
  183. ColumnConfiguration conf = grid.escalator
  184. .getColumnConfiguration();
  185. if (visible) {
  186. conf.insertColumns(index, 1);
  187. } else {
  188. conf.removeColumns(index, 1);
  189. }
  190. // TODO should update body as well
  191. }
  192. this.visible = visible;
  193. }
  194. /**
  195. * Returns the text that should be displayed in the cell.
  196. *
  197. * @param row
  198. * The row object that provides the cell content.
  199. *
  200. * @return The cell content
  201. */
  202. public abstract String getValue(T row);
  203. /**
  204. * Finds the index of this column instance
  205. *
  206. */
  207. private int findIndexOfColumn() {
  208. return grid.columns.indexOf(this);
  209. }
  210. }
  211. /**
  212. * Base class for header / footer escalator updater
  213. */
  214. protected abstract class HeaderFooterEscalatorUpdater implements
  215. EscalatorUpdater {
  216. /**
  217. * The row container which contains the header or footer rows
  218. */
  219. private RowContainer rows;
  220. /**
  221. * Should the index be counted from 0-> or 0<-
  222. */
  223. private boolean inverted;
  224. /**
  225. * Constructs an updater for updating a header / footer
  226. *
  227. * @param rows
  228. * The row container
  229. * @param inverted
  230. * Should index counting be inverted
  231. */
  232. public HeaderFooterEscalatorUpdater(RowContainer rows, boolean inverted) {
  233. this.rows = rows;
  234. this.inverted = inverted;
  235. }
  236. /**
  237. * Gets the header/footer caption value
  238. *
  239. * @return The value that should be rendered for the column caption
  240. */
  241. public abstract String getColumnValue(GridColumn column);
  242. /**
  243. * Gets the group caption value
  244. *
  245. * @param group
  246. * The group for with the caption value should be returned
  247. * @return The value that should be rendered for the column caption
  248. */
  249. public abstract String getGroupValue(ColumnGroup group);
  250. /**
  251. * Is the row visible in the header/footer
  252. *
  253. * @return <code>true</code> if the row should be visible
  254. */
  255. public abstract boolean isRowVisible(ColumnGroupRow row);
  256. /**
  257. * Should the first row be visible
  258. *
  259. * @return <code>true</code> if the first row should be visible
  260. */
  261. public abstract boolean firstRowIsVisible();
  262. @Override
  263. public void updateCells(Row row, List<Cell> cellsToUpdate) {
  264. int rowIndex;
  265. if (inverted) {
  266. rowIndex = rows.getRowCount() - row.getRow() - 1;
  267. } else {
  268. rowIndex = row.getRow();
  269. }
  270. if (firstRowIsVisible() && rowIndex == 0) {
  271. // column headers
  272. for (Cell cell : cellsToUpdate) {
  273. int columnIndex = cell.getColumn();
  274. GridColumn column = columns.get(columnIndex);
  275. cell.getElement().setInnerText(getColumnValue(column));
  276. }
  277. } else if (columnGroupRows.size() > 0) {
  278. // Adjust for headers
  279. if (firstRowIsVisible()) {
  280. rowIndex--;
  281. }
  282. // Adjust for previous invisible header rows
  283. ColumnGroupRow groupRow = null;
  284. for (int i = 0, realIndex = 0; i < columnGroupRows.size(); i++) {
  285. groupRow = columnGroupRows.get(i);
  286. if (isRowVisible(groupRow)) {
  287. if (realIndex == rowIndex) {
  288. rowIndex = realIndex;
  289. break;
  290. }
  291. realIndex++;
  292. }
  293. }
  294. assert groupRow != null;
  295. for (Cell cell : cellsToUpdate) {
  296. int columnIndex = cell.getColumn();
  297. GridColumn column = columns.get(columnIndex);
  298. ColumnGroup group = getGroupForColumn(groupRow, column);
  299. if (group != null) {
  300. // FIXME Should merge the group cells when escalator
  301. // supports it
  302. cell.getElement().setInnerText(getGroupValue(group));
  303. } else {
  304. // Cells are reused
  305. cell.getElement().setInnerHTML(null);
  306. }
  307. }
  308. }
  309. }
  310. }
  311. /**
  312. * Creates a new instance.
  313. */
  314. public Grid() {
  315. initWidget(escalator);
  316. escalator.getHeader().setEscalatorUpdater(createHeaderUpdater());
  317. escalator.getBody().setEscalatorUpdater(createBodyUpdater());
  318. escalator.getFooter().setEscalatorUpdater(createFooterUpdater());
  319. refreshHeader();
  320. refreshFooter();
  321. escalator
  322. .addRowVisibilityChangeHandler(new RowVisibilityChangeHandler() {
  323. @Override
  324. public void onRowVisibilityChange(
  325. RowVisibilityChangeEvent event) {
  326. if (dataSource != null) {
  327. dataSource.ensureAvailability(
  328. event.getFirstVisibleRow(),
  329. event.getVisibleRowCount());
  330. }
  331. }
  332. });
  333. }
  334. /**
  335. * Creates the header updater that updates the escalator header rows from
  336. * the column and column group rows.
  337. *
  338. * @return the updater that updates the data in the escalator.
  339. */
  340. private EscalatorUpdater createHeaderUpdater() {
  341. return new HeaderFooterEscalatorUpdater(escalator.getHeader(), true) {
  342. @Override
  343. public boolean isRowVisible(ColumnGroupRow row) {
  344. return row.isHeaderVisible();
  345. }
  346. @Override
  347. public String getGroupValue(ColumnGroup group) {
  348. return group.getHeaderCaption();
  349. }
  350. @Override
  351. public String getColumnValue(GridColumn column) {
  352. return column.getHeaderCaption();
  353. }
  354. @Override
  355. public boolean firstRowIsVisible() {
  356. return isColumnHeadersVisible();
  357. }
  358. };
  359. }
  360. private EscalatorUpdater createBodyUpdater() {
  361. return new EscalatorUpdater() {
  362. @Override
  363. public void updateCells(Row row, List<Cell> cellsToUpdate) {
  364. int rowIndex = row.getRow();
  365. if (dataSource == null) {
  366. setCellsLoading(cellsToUpdate);
  367. return;
  368. }
  369. T rowData = dataSource.getRow(rowIndex);
  370. if (rowData == null) {
  371. setCellsLoading(cellsToUpdate);
  372. return;
  373. }
  374. for (Cell cell : cellsToUpdate) {
  375. String value = getColumn(cell.getColumn())
  376. .getValue(rowData);
  377. cell.getElement().setInnerText(value);
  378. }
  379. }
  380. private void setCellsLoading(List<Cell> cellsToUpdate) {
  381. for (Cell cell : cellsToUpdate) {
  382. cell.getElement().setInnerText("...");
  383. }
  384. }
  385. };
  386. }
  387. /**
  388. * Creates the footer updater that updates the escalator footer rows from
  389. * the column and column group rows.
  390. *
  391. * @return the updater that updates the data in the escalator.
  392. */
  393. private EscalatorUpdater createFooterUpdater() {
  394. return new HeaderFooterEscalatorUpdater(escalator.getFooter(), false) {
  395. @Override
  396. public boolean isRowVisible(ColumnGroupRow row) {
  397. return row.isFooterVisible();
  398. }
  399. @Override
  400. public String getGroupValue(ColumnGroup group) {
  401. return group.getFooterCaption();
  402. }
  403. @Override
  404. public String getColumnValue(GridColumn column) {
  405. return column.getFooterCaption();
  406. }
  407. @Override
  408. public boolean firstRowIsVisible() {
  409. return isColumnFootersVisible();
  410. }
  411. };
  412. }
  413. /**
  414. * Refreshes header or footer rows on demand
  415. *
  416. * @param rows
  417. * The row container
  418. * @param firstRowIsVisible
  419. * is the first row visible
  420. * @param isHeader
  421. * <code>true</code> if we refreshing the header, else assumed
  422. * the footer
  423. */
  424. private void refreshRowContainer(RowContainer rows,
  425. boolean firstRowIsVisible, boolean isHeader) {
  426. // Count needed rows
  427. int totalRows = firstRowIsVisible ? 1 : 0;
  428. for (ColumnGroupRow row : columnGroupRows) {
  429. if (isHeader ? row.isHeaderVisible() : row.isFooterVisible()) {
  430. totalRows++;
  431. }
  432. }
  433. // Add or Remove rows on demand
  434. int rowDiff = totalRows - rows.getRowCount();
  435. if (rowDiff > 0) {
  436. rows.insertRows(0, rowDiff);
  437. } else if (rowDiff < 0) {
  438. rows.removeRows(0, -rowDiff);
  439. }
  440. // Refresh all the rows
  441. if (rows.getRowCount() > 0) {
  442. rows.refreshRows(0, rows.getRowCount());
  443. }
  444. }
  445. /**
  446. * Refreshes all header rows
  447. */
  448. void refreshHeader() {
  449. refreshRowContainer(escalator.getHeader(), isColumnHeadersVisible(),
  450. true);
  451. }
  452. /**
  453. * Refreshes all footer rows
  454. */
  455. void refreshFooter() {
  456. refreshRowContainer(escalator.getFooter(), isColumnFootersVisible(),
  457. false);
  458. }
  459. /**
  460. * Adds a column as the last column in the grid.
  461. *
  462. * @param column
  463. * the column to add
  464. */
  465. public void addColumn(GridColumn<T> column) {
  466. ColumnConfiguration conf = escalator.getColumnConfiguration();
  467. addColumn(column, conf.getColumnCount());
  468. }
  469. /**
  470. * Inserts a column into a specific position in the grid.
  471. *
  472. * @param index
  473. * the index where the column should be inserted into
  474. * @param column
  475. * the column to add
  476. */
  477. public void addColumn(GridColumn<T> column, int index) {
  478. // Register this grid instance with the column
  479. ((AbstractGridColumn<T>) column).setGrid(this);
  480. columns.add(index, column);
  481. ColumnConfiguration conf = escalator.getColumnConfiguration();
  482. conf.insertColumns(index, 1);
  483. }
  484. /**
  485. * Removes a column from the grid.
  486. *
  487. * @param column
  488. * the column to remove
  489. */
  490. public void removeColumn(GridColumn<T> column) {
  491. int columnIndex = columns.indexOf(column);
  492. columns.remove(columnIndex);
  493. // de-register column with grid
  494. ((AbstractGridColumn<T>) column).setGrid(null);
  495. ColumnConfiguration conf = escalator.getColumnConfiguration();
  496. conf.removeColumns(columnIndex, 1);
  497. }
  498. /**
  499. * Returns the amount of columns in the grid.
  500. *
  501. * @return The number of columns in the grid
  502. */
  503. public int getColumnCount() {
  504. return columns.size();
  505. }
  506. /**
  507. * Returns a list of columns in the grid.
  508. *
  509. * @return A unmodifiable list of the columns in the grid
  510. */
  511. public List<GridColumn<T>> getColumns() {
  512. return Collections.unmodifiableList(new ArrayList<GridColumn<T>>(
  513. columns));
  514. }
  515. /**
  516. * Returns a column by its index in the grid.
  517. *
  518. * @param index
  519. * the index of the column
  520. * @return The column in the given index
  521. * @throws IllegalArgumentException
  522. * if the column index does not exist in the grid
  523. */
  524. public GridColumn<T> getColumn(int index) throws IllegalArgumentException {
  525. if (index < 0 || index >= columns.size()) {
  526. throw new IllegalStateException("Column not found.");
  527. }
  528. return columns.get(index);
  529. }
  530. /**
  531. * Set the column headers visible.
  532. *
  533. * <p>
  534. * A column header is a single cell header on top of each column reserved
  535. * for a specific header for that column. The column header can be set by
  536. * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be
  537. * merged with other column headers.
  538. * </p>
  539. *
  540. * <p>
  541. * All column headers occupy the first header row of the grid. If you do not
  542. * wish to show the column headers in the grid you should hide the row by
  543. * setting visibility of the header row to <code>false</code>.
  544. * </p>
  545. *
  546. * <p>
  547. * If you want to merge the column headers into groups you can use
  548. * {@link ColumnGroupRow}s to group columns together and give them a common
  549. * header. See {@link #addColumnGroupRow()} for details.
  550. * </p>
  551. *
  552. * <p>
  553. * The header row is by default visible.
  554. * </p>
  555. *
  556. * @param visible
  557. * <code>true</code> if header rows should be visible
  558. */
  559. public void setColumnHeadersVisible(boolean visible) {
  560. if (visible == isColumnHeadersVisible()) {
  561. return;
  562. }
  563. columnHeadersVisible = visible;
  564. refreshHeader();
  565. }
  566. /**
  567. * Are the column headers visible
  568. *
  569. * @return <code>true</code> if they are visible
  570. */
  571. public boolean isColumnHeadersVisible() {
  572. return columnHeadersVisible;
  573. }
  574. /**
  575. * Set the column footers visible.
  576. *
  577. * <p>
  578. * A column footer is a single cell footer below of each column reserved for
  579. * a specific footer for that column. The column footer can be set by
  580. * {@link GridColumn#setFooterCaption(String)} and column footers cannot be
  581. * merged with other column footers.
  582. * </p>
  583. *
  584. * <p>
  585. * All column footers occupy the first footer row of the grid. If you do not
  586. * wish to show the column footers in the grid you should hide the row by
  587. * setting visibility of the footer row to <code>false</code>.
  588. * </p>
  589. *
  590. * <p>
  591. * If you want to merge the column footers into groups you can use
  592. * {@link ColumnGroupRow}s to group columns together and give them a common
  593. * footer. See {@link #addColumnGroupRow()} for details.
  594. * </p>
  595. *
  596. * <p>
  597. * The footer row is by default hidden.
  598. * </p>
  599. *
  600. * @param visible
  601. * <code>true</code> if the footer row should be visible
  602. */
  603. public void setColumnFootersVisible(boolean visible) {
  604. if (visible == isColumnFootersVisible()) {
  605. return;
  606. }
  607. this.columnFootersVisible = visible;
  608. refreshFooter();
  609. }
  610. /**
  611. * Are the column footers visible
  612. *
  613. * @return <code>true</code> if they are visible
  614. *
  615. */
  616. public boolean isColumnFootersVisible() {
  617. return columnFootersVisible;
  618. }
  619. /**
  620. * Adds a new column group row to the grid.
  621. *
  622. * <p>
  623. * Column group rows are rendered in the header and footer of the grid.
  624. * Column group rows are made up of column groups which groups together
  625. * columns for adding a common auxiliary header or footer for the columns.
  626. * </p>
  627. *
  628. * Example usage:
  629. *
  630. * <pre>
  631. * // Add a new column group row to the grid
  632. * ColumnGroupRow row = grid.addColumnGroupRow();
  633. *
  634. * // Group &quot;Column1&quot; and &quot;Column2&quot; together to form a header in the row
  635. * ColumnGroup column12 = row.addGroup(&quot;Column1&quot;, &quot;Column2&quot;);
  636. *
  637. * // Set a common header for &quot;Column1&quot; and &quot;Column2&quot;
  638. * column12.setHeader(&quot;Column 1&amp;2&quot;);
  639. *
  640. * // Set a common footer for &quot;Column1&quot; and &quot;Column2&quot;
  641. * column12.setFooter(&quot;Column 1&amp;2&quot;);
  642. * </pre>
  643. *
  644. * @return a column group row instance you can use to add column groups
  645. */
  646. public ColumnGroupRow addColumnGroupRow() {
  647. ColumnGroupRow row = new ColumnGroupRow(this);
  648. columnGroupRows.add(row);
  649. refreshHeader();
  650. refreshFooter();
  651. return row;
  652. }
  653. /**
  654. * Adds a new column group row to the grid at a specific index.
  655. *
  656. * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example
  657. * usage
  658. *
  659. * @param rowIndex
  660. * the index where the column group row should be added
  661. * @return a column group row instance you can use to add column groups
  662. */
  663. public ColumnGroupRow addColumnGroupRow(int rowIndex) {
  664. ColumnGroupRow row = new ColumnGroupRow(this);
  665. columnGroupRows.add(rowIndex, row);
  666. refreshHeader();
  667. refreshFooter();
  668. return row;
  669. }
  670. /**
  671. * Removes a column group row
  672. *
  673. * @param row
  674. * The row to remove
  675. */
  676. public void removeColumnGroupRow(ColumnGroupRow row) {
  677. columnGroupRows.remove(row);
  678. refreshHeader();
  679. refreshFooter();
  680. }
  681. /**
  682. * Get the column group rows
  683. *
  684. * @return a unmodifiable list of column group rows
  685. *
  686. */
  687. public List<ColumnGroupRow> getColumnGroupRows() {
  688. return Collections.unmodifiableList(new ArrayList<ColumnGroupRow>(
  689. columnGroupRows));
  690. }
  691. /**
  692. * Returns the column group for a row and column
  693. *
  694. * @param row
  695. * The row of the column
  696. * @param column
  697. * the column to get the group for
  698. * @return A column group for the row and column or <code>null</code> if not
  699. * found.
  700. */
  701. private static ColumnGroup getGroupForColumn(ColumnGroupRow row,
  702. GridColumn column) {
  703. for (ColumnGroup group : row.getGroups()) {
  704. List<GridColumn> columns = group.getColumns();
  705. if (columns.contains(column)) {
  706. return group;
  707. }
  708. }
  709. return null;
  710. }
  711. @Override
  712. public void setHeight(String height) {
  713. escalator.setHeight(height);
  714. }
  715. @Override
  716. public void setWidth(String width) {
  717. escalator.setWidth(width);
  718. }
  719. /**
  720. * Sets the data source used by this grid.
  721. *
  722. * @param dataSource
  723. * the data source to use, not null
  724. * @throws IllegalArgumentException
  725. * if <code>dataSource</code> is <code>null</code>
  726. */
  727. public void setDataSource(DataSource<T> dataSource)
  728. throws IllegalArgumentException {
  729. if (dataSource == null) {
  730. throw new IllegalArgumentException("dataSource can't be null.");
  731. }
  732. if (this.dataSource != null) {
  733. this.dataSource.setDataChangeHandler(null);
  734. }
  735. this.dataSource = dataSource;
  736. dataSource.setDataChangeHandler(new DataChangeHandler() {
  737. @Override
  738. public void dataUpdated(int firstIndex, int numberOfItems) {
  739. escalator.getBody().refreshRows(firstIndex, numberOfItems);
  740. }
  741. @Override
  742. public void dataRemoved(int firstIndex, int numberOfItems) {
  743. escalator.getBody().removeRows(firstIndex, numberOfItems);
  744. }
  745. @Override
  746. public void dataAdded(int firstIndex, int numberOfItems) {
  747. escalator.getBody().insertRows(firstIndex, numberOfItems);
  748. }
  749. });
  750. int previousRowCount = escalator.getBody().getRowCount();
  751. if (previousRowCount != 0) {
  752. escalator.getBody().removeRows(0, previousRowCount);
  753. }
  754. int estimatedSize = dataSource.getEstimatedSize();
  755. if (estimatedSize > 0) {
  756. escalator.getBody().insertRows(0, estimatedSize);
  757. }
  758. }
  759. }