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.sample.dynatable.client;
017:
018: import com.google.gwt.sample.dynatable.client.DynaTableDataProvider.RowDataAcceptor;
019: import com.google.gwt.user.client.rpc.InvocationException;
020: import com.google.gwt.user.client.ui.Button;
021: import com.google.gwt.user.client.ui.ClickListener;
022: import com.google.gwt.user.client.ui.Composite;
023: import com.google.gwt.user.client.ui.DialogBox;
024: import com.google.gwt.user.client.ui.DockPanel;
025: import com.google.gwt.user.client.ui.Grid;
026: import com.google.gwt.user.client.ui.HTML;
027: import com.google.gwt.user.client.ui.HasAlignment;
028: import com.google.gwt.user.client.ui.HorizontalPanel;
029: import com.google.gwt.user.client.ui.VerticalPanel;
030: import com.google.gwt.user.client.ui.Widget;
031:
032: /**
033: * A composite Widget that implements the main interface for the dynamic table,
034: * including the data table, status indicators, and paging buttons.
035: */
036: public class DynaTableWidget extends Composite {
037:
038: /**
039: * A dialog box for displaying an error.
040: */
041: private static class ErrorDialog extends DialogBox implements
042: ClickListener {
043: private HTML body = new HTML("");
044:
045: public ErrorDialog() {
046: setStylePrimaryName("DynaTable-ErrorDialog");
047: Button closeButton = new Button("Close", this );
048: VerticalPanel panel = new VerticalPanel();
049: panel.setSpacing(4);
050: panel.add(body);
051: panel.add(closeButton);
052: panel.setCellHorizontalAlignment(closeButton,
053: VerticalPanel.ALIGN_RIGHT);
054: setWidget(panel);
055: }
056:
057: public String getBody() {
058: return body.getHTML();
059: }
060:
061: public void onClick(Widget sender) {
062: hide();
063: }
064:
065: public void setBody(String html) {
066: body.setHTML(html);
067: }
068: }
069:
070: private class NavBar extends Composite implements ClickListener {
071:
072: public final DockPanel bar = new DockPanel();
073: public final Button gotoFirst = new Button("<<", this );
074: public final Button gotoNext = new Button(">", this );
075: public final Button gotoPrev = new Button("<", this );
076: public final HTML status = new HTML();
077:
078: public NavBar() {
079: initWidget(bar);
080: bar.setStyleName("navbar");
081: status.setStyleName("status");
082:
083: HorizontalPanel buttons = new HorizontalPanel();
084: buttons.add(gotoFirst);
085: buttons.add(gotoPrev);
086: buttons.add(gotoNext);
087: bar.add(buttons, DockPanel.EAST);
088: bar.setCellHorizontalAlignment(buttons,
089: DockPanel.ALIGN_RIGHT);
090: bar.add(status, DockPanel.CENTER);
091: bar.setVerticalAlignment(DockPanel.ALIGN_MIDDLE);
092: bar.setCellHorizontalAlignment(status,
093: HasAlignment.ALIGN_RIGHT);
094: bar.setCellVerticalAlignment(status,
095: HasAlignment.ALIGN_MIDDLE);
096: bar.setCellWidth(status, "100%");
097:
098: // Initialize prev & first button to disabled.
099: //
100: gotoPrev.setEnabled(false);
101: gotoFirst.setEnabled(false);
102: }
103:
104: public void onClick(Widget sender) {
105: if (sender == gotoNext) {
106: startRow += getDataRowCount();
107: refresh();
108: } else if (sender == gotoPrev) {
109: startRow -= getDataRowCount();
110: if (startRow < 0) {
111: startRow = 0;
112: }
113: refresh();
114: } else if (sender == gotoFirst) {
115: startRow = 0;
116: refresh();
117: }
118: }
119: }
120:
121: private class RowDataAcceptorImpl implements RowDataAcceptor {
122: public void accept(int startRow, String[][] data) {
123:
124: int destRowCount = getDataRowCount();
125: int destColCount = grid.getCellCount(0);
126: assert (data.length <= destRowCount) : "Too many rows";
127:
128: int srcRowIndex = 0;
129: int srcRowCount = data.length;
130: int destRowIndex = 1; // skip navbar row
131: for (; srcRowIndex < srcRowCount; ++srcRowIndex, ++destRowIndex) {
132: String[] srcRowData = data[srcRowIndex];
133: assert (srcRowData.length == destColCount) : " Column count mismatch";
134: for (int srcColIndex = 0; srcColIndex < destColCount; ++srcColIndex) {
135: String cellHTML = srcRowData[srcColIndex];
136: grid.setText(destRowIndex, srcColIndex, cellHTML);
137: }
138: }
139:
140: // Clear remaining table rows.
141: //
142: boolean isLastPage = false;
143: for (; destRowIndex < destRowCount + 1; ++destRowIndex) {
144: isLastPage = true;
145: for (int destColIndex = 0; destColIndex < destColCount; ++destColIndex) {
146: grid.clearCell(destRowIndex, destColIndex);
147: }
148: }
149:
150: // Synchronize the nav buttons.
151: navbar.gotoNext.setEnabled(!isLastPage);
152: navbar.gotoFirst.setEnabled(startRow > 0);
153: navbar.gotoPrev.setEnabled(startRow > 0);
154:
155: // Update the status message.
156: //
157: setStatusText((startRow + 1) + " - "
158: + (startRow + srcRowCount));
159: }
160:
161: public void failed(Throwable caught) {
162: setStatusText("Error");
163: if (errorDialog == null) {
164: errorDialog = new ErrorDialog();
165: }
166: if (caught instanceof InvocationException) {
167: errorDialog
168: .setText("An RPC server could not be reached");
169: errorDialog.setBody(NO_CONNECTION_MESSAGE);
170: } else {
171: errorDialog
172: .setText("Unexcepted Error processing remote call");
173: errorDialog.setBody(caught.getMessage());
174: }
175: errorDialog.center();
176: }
177: }
178:
179: private static final String NO_CONNECTION_MESSAGE = "<p>The DynaTable example uses a <a href=\"http://code.google.com/"
180: + "webtoolkit/documentation/com.google.gwt.doc.DeveloperGuide."
181: + "RemoteProcedureCalls.html\" target=\"_blank\">Remote Procedure Call</a> "
182: + "(RPC) to request data from the server. In order for the RPC to "
183: + "successfully return data, the server component must be available.</p>"
184: + "<p>If you are running this demo from compiled code, the server "
185: + "component may not be available to respond to the RPC requests from "
186: + "DynaTable. Try running DynaTable in hosted mode to see the demo "
187: + "in action.</p> "
188: + "<p>Click on the Remote Procedure Call link above for more information "
189: + "on GWT's RPC infrastructure.";
190:
191: private final RowDataAcceptor acceptor = new RowDataAcceptorImpl();
192:
193: private final Grid grid = new Grid();
194:
195: private final NavBar navbar = new NavBar();
196:
197: private ErrorDialog errorDialog = null;
198:
199: private final DockPanel outer = new DockPanel();
200:
201: private final DynaTableDataProvider provider;
202:
203: private int startRow = 0;
204:
205: public DynaTableWidget(DynaTableDataProvider provider,
206: String[] columns, String[] columnStyles, int rowCount) {
207:
208: if (columns.length == 0) {
209: throw new IllegalArgumentException(
210: "expecting a positive number of columns");
211: }
212:
213: if (columnStyles != null
214: && columns.length != columnStyles.length) {
215: throw new IllegalArgumentException(
216: "expecting as many styles as columns");
217: }
218:
219: this .provider = provider;
220: initWidget(outer);
221: grid.setStyleName("table");
222: outer.add(navbar, DockPanel.NORTH);
223: outer.add(grid, DockPanel.CENTER);
224: initTable(columns, columnStyles, rowCount);
225: setStyleName("DynaTable-DynaTableWidget");
226: }
227:
228: public void clearStatusText() {
229: navbar.status.setHTML(" ");
230: }
231:
232: public void refresh() {
233: // Disable buttons temporarily to stop the user from running off the end.
234: //
235: navbar.gotoFirst.setEnabled(false);
236: navbar.gotoPrev.setEnabled(false);
237: navbar.gotoNext.setEnabled(false);
238:
239: setStatusText("Please wait...");
240: provider.updateRowData(startRow, grid.getRowCount() - 1,
241: acceptor);
242: }
243:
244: public void setRowCount(int rows) {
245: grid.resizeRows(rows);
246: }
247:
248: public void setStatusText(String text) {
249: navbar.status.setText(text);
250: }
251:
252: private int getDataRowCount() {
253: return grid.getRowCount() - 1;
254: }
255:
256: private void initTable(String[] columns, String[] columnStyles,
257: int rowCount) {
258: // Set up the header row. It's one greater than the number of visible rows.
259: //
260: grid.resize(rowCount + 1, columns.length);
261: for (int i = 0, n = columns.length; i < n; i++) {
262: grid.setText(0, i, columns[i]);
263: if (columnStyles != null) {
264: grid.getCellFormatter().setStyleName(0, i,
265: columnStyles[i] + " header");
266: }
267: }
268: }
269: }
|