2 * Copyright (C) 2011 Openismus GmbH
4 * This file is part of GWT-Glom.
6 * GWT-Glom is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
11 * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with GWT-Glom. If not, see <http://www.gnu.org/licenses/>.
20 package org.glom.web.client.ui.list;
22 import java.util.ArrayList;
24 import org.glom.web.client.Utils;
25 import org.glom.web.client.ui.cell.BooleanCell;
26 import org.glom.web.client.ui.cell.NumericCell;
27 import org.glom.web.client.ui.cell.OpenButtonCell;
28 import org.glom.web.client.ui.cell.TextCell;
29 import org.glom.web.shared.DataItem;
30 import org.glom.web.shared.GlomNumericFormat;
31 import org.glom.web.shared.layout.Formatting;
32 import org.glom.web.shared.layout.LayoutGroup;
33 import org.glom.web.shared.layout.LayoutItem;
34 import org.glom.web.shared.layout.LayoutItemField;
35 import org.glom.web.shared.layout.LayoutItemField.GlomFieldType;
37 import com.google.gwt.event.shared.EventBus;
38 import com.google.gwt.i18n.client.NumberFormat;
39 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
40 import com.google.gwt.user.cellview.client.CellTable;
41 import com.google.gwt.user.cellview.client.Column;
42 import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler;
43 import com.google.gwt.user.cellview.client.SafeHtmlHeader;
44 import com.google.gwt.user.cellview.client.SimplePager;
45 import com.google.gwt.user.client.ui.Composite;
46 import com.google.gwt.user.client.ui.FlowPanel;
47 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
48 import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
49 import com.google.gwt.view.client.AbstractDataProvider;
50 import com.google.gwt.view.client.ProvidesKey;
53 * @author Ben Konrath <ben@bagu.org>
56 public abstract class ListTable extends Composite {
58 private class ListTablePager extends SimplePager {
59 public ListTablePager() {
60 super(SimplePager.TextLocation.CENTER);
64 * A custom version of createText to display the correct number of data row when empty rows have been added to
65 * the CellTable. This method is needed because the row count change event handler
66 * (AbstractPager.handleRowCountChange()) doesn't use the row count that is sent along with the
67 * RowCountChangeEvent.
69 * @see com.google.gwt.user.cellview.client.AbstractPager#handleRowCountChange(int, boolean)
71 * @see com.google.gwt.user.cellview.client.SimplePager#createText()
74 protected String createText() {
75 int numNonEmptyRows = getNumNonEmptyRows();
76 if (numNonEmptyRows < getMinNumVisibleRows()) {
77 NumberFormat formatter = NumberFormat.getFormat("#,###");
78 return formatter.format(1) + "-" + formatter.format(numNonEmptyRows) + " of "
79 + formatter.format(numNonEmptyRows);
81 return super.createText();
86 final private FlowPanel mainPanel = new FlowPanel();
87 final private ListTablePager pager = new ListTablePager();
88 protected String documentID;
89 protected String tableName;
90 protected CellTable<DataItem[]> cellTable;
91 protected EventBus eventBus;
93 abstract protected AbstractDataProvider<DataItem[]> getDataProvider();
95 @SuppressWarnings("unused")
97 // disable default constructor
100 public ListTable(String documentID) {
101 this.documentID = documentID;
104 public void createCellTable(LayoutGroup layoutGroup, int numVisibleRows) {
106 tableName = layoutGroup.getTableName();
107 ArrayList<LayoutItem> layoutItems = layoutGroup.getItems();
109 final int primaryKeyIndex = layoutGroup.getPrimaryKeyIndex();
110 LayoutItemField primaryKeyLayoutItem = (LayoutItemField) layoutItems.get(primaryKeyIndex);
111 final GlomFieldType primaryKeyFieldType = primaryKeyLayoutItem.getType();
112 ProvidesKey<DataItem[]> keyProvider = new ProvidesKey<DataItem[]>() {
114 public Object getKey(DataItem[] row) {
115 if (row.length == 1 && row[0] == null)
118 return Utils.getTypedDataItem(primaryKeyFieldType, row[primaryKeyIndex]);
122 // create the CellTable with the requested number of rows and the key provider
123 cellTable = new CellTable<DataItem[]>(numVisibleRows, keyProvider);
126 cellTable.setStyleName("data-list");
127 cellTable.getElement().getStyle().setProperty("whiteSpace", "nowrap"); // this prevents the header and row text
130 // add columns to the CellTable and deal with the case of the hidden primary key
131 int numItems = layoutGroup.hasHiddenPrimaryKey() ? layoutItems.size() - 1 : layoutItems.size();
132 for (int i = 0; i < numItems; i++) {
133 LayoutItem layoutItem = layoutItems.get(i);
135 // only add columns for LayoutItemField types
136 if (layoutItem instanceof LayoutItemField) {
137 addColumn((LayoutItemField) layoutItem);
142 // create and set the data provider
143 AbstractDataProvider<DataItem[]> dataProvider = getDataProvider();
144 dataProvider.addDataDisplay(cellTable);
146 // add an AsyncHandler to activate sorting for the data provider
147 cellTable.addColumnSortHandler(new AsyncHandler(cellTable));
149 // pack the widgets into the container
150 pager.setDisplay(cellTable);
151 mainPanel.add(cellTable);
152 mainPanel.add(pager);
154 // initialize composite widget
155 initWidget(mainPanel);
158 public void addColumn(final LayoutItemField layoutItemField) {
159 // Setup the default alignment of the column.
160 HorizontalAlignmentConstant columnAlignment;
161 Formatting formatting = layoutItemField.getFormatting();
162 switch (formatting.getHorizontalAlignment()) {
163 case HORIZONTAL_ALIGNMENT_LEFT:
164 columnAlignment = HasHorizontalAlignment.ALIGN_LEFT;
166 case HORIZONTAL_ALIGNMENT_RIGHT:
167 columnAlignment = HasHorizontalAlignment.ALIGN_RIGHT;
169 case HORIZONTAL_ALIGNMENT_AUTO:
171 columnAlignment = HasHorizontalAlignment.ALIGN_DEFAULT;
175 // create a new column
176 Column<DataItem[], ?> column = null;
177 final int j = cellTable.getColumnCount();
178 switch (layoutItemField.getType()) {
181 column = new Column<DataItem[], Boolean>(new BooleanCell()) {
183 public Boolean getValue(DataItem[] row) {
184 if (row.length == 1 && row[0] == null)
187 return row[j].getBoolean();
190 // override the configured horizontal alignment
191 columnAlignment = HasHorizontalAlignment.ALIGN_CENTER;
195 // create a GWT NumberFormat for the column
196 GlomNumericFormat glomNumericFormat = formatting.getGlomNumericFormat();
197 NumberFormat gwtNumberFormat = Utils.getNumberFormat(glomNumericFormat);
199 // create the actual column
200 column = new Column<DataItem[], Double>(new NumericCell(formatting.getTextFormatColourForeground(),
201 formatting.getTextFormatColourBackground(), gwtNumberFormat,
202 glomNumericFormat.getUseAltForegroundColourForNegatives(), glomNumericFormat.getCurrencyCode())) {
204 public Double getValue(DataItem[] row) {
205 if (row.length == 1 && row[0] == null)
208 return row[j].getNumber();
214 // use a text rendering cell for types we don't know about but log an error
215 // TODO log error here
221 column = new Column<DataItem[], String>(new TextCell(formatting.getTextFormatColourForeground(),
222 formatting.getTextFormatColourBackground())) {
224 public String getValue(DataItem[] row) {
225 if (row.length == 1 && row[0] == null)
228 return row[j].getText();
234 // set column properties and add to cell cellTable
235 column.setHorizontalAlignment(columnAlignment);
236 column.setSortable(true);
237 cellTable.addColumn(column, new SafeHtmlHeader(SafeHtmlUtils.fromString(layoutItemField.getTitle())));
240 public void addOpenButtonColumn(final String openButtonLabel, OpenButtonCell openButtonCell) {
242 Column<DataItem[], String> openButtonColumn = new Column<DataItem[], String>(openButtonCell) {
244 public String getValue(DataItem[] row) {
245 if (row.length == 1 && row[0] == null)
248 return openButtonLabel;
252 // the style name for the details column is set on the col element
253 cellTable.addColumnStyleName(cellTable.getColumnCount() - 1, "details");
255 // Firefox, Chrome, and Safari only support the span and width attributes of the col element so we need to set
256 // the alignment with code
257 openButtonColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
259 cellTable.addColumn(openButtonColumn, "");
264 * Sets the row count for the pager.
266 public void setRowCount(int rowCount) {
267 cellTable.setRowCount(rowCount);
271 * Gets the minimum number of rows the should be displayed. Empty rows will be added when the query returns fewer
272 * rows than this minimum.
274 * @return The minimum number of rows that should be displayed.
276 public abstract int getMinNumVisibleRows();
278 public abstract int getNumNonEmptyRows();