2 * Copyright (C) 2010, 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;
22 import java.util.ArrayList;
24 import org.glom.web.client.OnlineGlomServiceAsync;
25 import org.glom.web.shared.ColumnInfo;
26 import org.glom.web.shared.GlomField;
28 import com.google.gwt.cell.client.AbstractCell;
29 import com.google.gwt.cell.client.ButtonCell;
30 import com.google.gwt.cell.client.CheckboxCell;
31 import com.google.gwt.cell.client.ValueUpdater;
32 import com.google.gwt.dom.client.Element;
33 import com.google.gwt.dom.client.InputElement;
34 import com.google.gwt.dom.client.NativeEvent;
35 import com.google.gwt.event.dom.client.KeyCodes;
36 import com.google.gwt.safehtml.shared.SafeHtml;
37 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
38 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
39 import com.google.gwt.user.cellview.client.CellTable;
40 import com.google.gwt.user.cellview.client.Column;
41 import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler;
42 import com.google.gwt.user.cellview.client.ColumnSortList;
43 import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
44 import com.google.gwt.user.cellview.client.SafeHtmlHeader;
45 import com.google.gwt.user.cellview.client.SimplePager;
46 import com.google.gwt.user.client.rpc.AsyncCallback;
47 import com.google.gwt.user.client.ui.Composite;
48 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
49 import com.google.gwt.user.client.ui.VerticalPanel;
50 import com.google.gwt.view.client.AsyncDataProvider;
51 import com.google.gwt.view.client.HasData;
52 import com.google.gwt.view.client.Range;
54 public class LayoutListView extends Composite {
56 private class GlomTextCell extends AbstractCell<GlomField> {
58 // The SafeHtml class is used to escape strings to avoid XSS attacks. This is not strictly
59 // necessary because the values aren't coming from a user but I'm using it anyway as a reminder.
61 public void render(Context context, GlomField value, SafeHtmlBuilder sb) {
66 // get the foreground and background colours if they're set
67 SafeHtml fgcolour = null, bgcolour = null;
68 String colour = value.getFGColour();
70 fgcolour = SafeHtmlUtils.fromSafeConstant("");
72 fgcolour = SafeHtmlUtils.fromString("color:" + colour + ";");
74 colour = value.getBGColour();
76 bgcolour = SafeHtmlUtils.fromSafeConstant("");
78 bgcolour = SafeHtmlUtils.fromString("background-color:" + colour + ";");
81 // set the text and colours
82 sb.appendHtmlConstant("<div style=\"" + fgcolour.asString() + bgcolour.asString() + "\">");
83 sb.append(SafeHtmlUtils.fromString(value.getText()));
84 sb.appendHtmlConstant("</div>");
88 public LayoutListView(ColumnInfo[] columns, int numRows) {
89 final CellTable<GlomField[]> table = new CellTable<GlomField[]>(20);
91 AsyncDataProvider<GlomField[]> dataProvider = new AsyncDataProvider<GlomField[]>() {
93 @SuppressWarnings("unchecked")
94 protected void onRangeChanged(HasData<GlomField[]> display) {
95 // setup the callback object
96 final Range range = display.getVisibleRange();
97 final int start = range.getStart();
98 AsyncCallback<ArrayList<GlomField[]>> callback = new AsyncCallback<ArrayList<GlomField[]>>() {
99 public void onFailure(Throwable caught) {
100 // FIXME: need to deal with failure
101 System.out.println("AsyncCallback Failed: OnlineGlomService.getTableData()");
104 public void onSuccess(ArrayList<GlomField[]> result) {
105 updateRowData(start, result);
109 // get data from the server
110 ColumnSortList colSortList = table.getColumnSortList();
111 if (colSortList.size() > 0) {
112 // ColumnSortEvent has been requested by the user
113 ColumnSortInfo info = colSortList.get(0);
114 OnlineGlomServiceAsync.Util.getInstance().getSortedTableData(OnlineGlomView.getCurrentTableName(),
115 start, range.getLength(), table.getColumnIndex((Column<GlomField[], ?>) info.getColumn()),
116 info.isAscending(), callback);
118 OnlineGlomServiceAsync.Util.getInstance().getTableData(OnlineGlomView.getCurrentTableName(), start,
119 range.getLength(), callback);
124 dataProvider.addDataDisplay(table);
126 SimplePager pager = new SimplePager(SimplePager.TextLocation.CENTER);
127 pager.setDisplay(table);
129 // a panel to hold our widgets
130 VerticalPanel panel = new VerticalPanel();
134 // create instances of GlomFieldColumn to retrieve the GlomField objects
135 for (int i = 0; i < columns.length; i++) {
136 // create a new column
137 Column<GlomField[], ?> column = null;
138 final int j = new Integer(i);
140 switch (columns[i].getType()) {
142 // The onBrowserEvent method is overridden to ensure the user can't toggle the checkbox. We'll probably
143 // be able to use a CheckboxCell directly when we add support for editing.
144 column = new Column<GlomField[], Boolean>(new CheckboxCell(false, false) {
146 public void onBrowserEvent(Context context, Element parent, Boolean value, NativeEvent event,
147 ValueUpdater<Boolean> valueUpdater) {
148 String type = event.getType();
150 boolean enterPressed = "keydown".equals(type) && event.getKeyCode() == KeyCodes.KEY_ENTER;
151 if ("change".equals(type) || enterPressed) {
152 InputElement input = parent.getFirstChild().cast();
153 input.setChecked(!input.isChecked());
158 public Boolean getValue(GlomField[] object) {
159 return object[j].getBoolean();
162 // Make checkboxes centred in the column.
163 column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
166 // use a text rendering cell for types we don't know about but log an error
167 // TODO log error here
174 // All of these types are formatted as text in the servlet.
175 column = new Column<GlomField[], GlomField>(new GlomTextCell()) {
177 public GlomField getValue(GlomField[] object) {
182 // Set the alignment of the text.
183 switch (columns[i].getAlignment()) {
184 case HORIZONTAL_ALIGNMENT_LEFT:
185 column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
187 case HORIZONTAL_ALIGNMENT_RIGHT:
188 column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
190 case HORIZONTAL_ALIGNMENT_AUTO:
192 // TODO: log warning, this shouldn't happen
193 column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_DEFAULT);
199 // set column properties and add to cell table
200 column.setSortable(true);
201 table.addColumn(column, new SafeHtmlHeader(SafeHtmlUtils.fromString(columns[i].getHeader())));
204 Column<GlomField[], String> detailsColumn = new Column<GlomField[], String>(new ButtonCell() {
206 public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
207 // TODO Enable the Details button: remove disabled=\"disabled\", add
208 // onclick=\"window.location.href='#targetHistoryToken'\", figure out how to create a history token to
209 // uniquely identify the row.
210 // TODO change to custom css class
211 // We're using a button tag for the link. If this causes a problem we can use an anchor tag with css
213 // to make it look like a button.
214 sb.appendHtmlConstant("<button class=\"gwt-Button\" title=\"Go to the details view for this row\" disabled=\"disabled\" type=\"button\" tabindex=\"-1\" >");
218 sb.appendHtmlConstant("</button>");
222 public String getValue(GlomField[] object) {
227 table.addColumn(detailsColumn, "");
229 // set row count which is needed for paging
230 table.setRowCount(numRows);
232 // add an AsyncHandler to activate sorting for the AsyncDataProvider that was created above
233 table.addColumnSortHandler(new AsyncHandler(table));
235 // take care of the stuff required for composite widgets
237 setStyleName("glom-LayoutListView");