/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.sample.dynatable.client; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.sample.dynatable.client.DynaTableDataProvider.RowDataAcceptor; import com.google.gwt.user.client.rpc.InvocationException; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DialogBox; import com.google.gwt.user.client.ui.DockPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.VerticalPanel; /** * A composite Widget that implements the main interface for the dynamic table, * including the data table, status indicators, and paging buttons. */ public class DynaTableWidget extends Composite { /** * A dialog box for displaying an error. */ private static class ErrorDialog extends DialogBox implements ClickHandler { private HTML body = new HTML(""); public ErrorDialog() { setStylePrimaryName("DynaTable-ErrorDialog"); Button closeButton = new Button("Close", this); VerticalPanel panel = new VerticalPanel(); panel.setSpacing(4); panel.add(body); panel.add(closeButton); panel.setCellHorizontalAlignment(closeButton, VerticalPanel.ALIGN_RIGHT); setWidget(panel); } public String getBody() { return body.getHTML(); } public void onClick(ClickEvent event) { hide(); } public void setBody(String html) { body.setHTML(html); } } private class NavBar extends Composite implements ClickHandler { public final DockPanel bar = new DockPanel(); public final Button gotoFirst = new Button("<<", this); public final Button gotoNext = new Button(">", this); public final Button gotoPrev = new Button("<", this); public final HTML status = new HTML(); public NavBar() { initWidget(bar); bar.setStyleName("navbar"); status.setStyleName("status"); HorizontalPanel buttons = new HorizontalPanel(); buttons.add(gotoFirst); buttons.add(gotoPrev); buttons.add(gotoNext); bar.add(buttons, DockPanel.EAST); bar.setCellHorizontalAlignment(buttons, DockPanel.ALIGN_RIGHT); bar.add(status, DockPanel.CENTER); bar.setVerticalAlignment(DockPanel.ALIGN_MIDDLE); bar.setCellHorizontalAlignment(status, HasAlignment.ALIGN_RIGHT); bar.setCellVerticalAlignment(status, HasAlignment.ALIGN_MIDDLE); bar.setCellWidth(status, "100%"); // Initialize prev & first button to disabled. // gotoPrev.setEnabled(false); gotoFirst.setEnabled(false); } public void onClick(ClickEvent event) { Object source = event.getSource(); if (source == gotoNext) { startRow += getDataRowCount(); refresh(); } else if (source == gotoPrev) { startRow -= getDataRowCount(); if (startRow < 0) { startRow = 0; } refresh(); } else if (source == gotoFirst) { startRow = 0; refresh(); } } } private class RowDataAcceptorImpl implements RowDataAcceptor { public void accept(int startRow, String[][] data) { int destRowCount = getDataRowCount(); int destColCount = grid.getCellCount(0); assert (data.length <= destRowCount) : "Too many rows"; int srcRowIndex = 0; int srcRowCount = data.length; int destRowIndex = 1; // skip navbar row for (; srcRowIndex < srcRowCount; ++srcRowIndex, ++destRowIndex) { String[] srcRowData = data[srcRowIndex]; assert (srcRowData.length == destColCount) : " Column count mismatch"; for (int srcColIndex = 0; srcColIndex < destColCount; ++srcColIndex) { String cellHTML = srcRowData[srcColIndex]; grid.setText(destRowIndex, srcColIndex, cellHTML); } } // Clear remaining table rows. // boolean isLastPage = false; for (; destRowIndex < destRowCount + 1; ++destRowIndex) { isLastPage = true; for (int destColIndex = 0; destColIndex < destColCount; ++destColIndex) { grid.clearCell(destRowIndex, destColIndex); } } // Synchronize the nav buttons. navbar.gotoNext.setEnabled(!isLastPage); navbar.gotoFirst.setEnabled(startRow > 0); navbar.gotoPrev.setEnabled(startRow > 0); // Update the status message. // setStatusText((startRow + 1) + " - " + (startRow + srcRowCount)); } public void failed(Throwable caught) { setStatusText("Error"); if (errorDialog == null) { errorDialog = new ErrorDialog(); } if (caught instanceof InvocationException) { errorDialog.setText("An RPC server could not be reached"); errorDialog.setBody(NO_CONNECTION_MESSAGE); } else { errorDialog.setText("Unexcepted Error processing remote call"); errorDialog.setBody(caught.getMessage()); } errorDialog.center(); } } private static final String NO_CONNECTION_MESSAGE = "<p>The DynaTable example uses a <a href=\"http://code.google.com/" + "webtoolkit/documentation/com.google.gwt.doc.DeveloperGuide." + "RemoteProcedureCalls.html\" target=\"_blank\">Remote Procedure Call</a> " + "(RPC) to request data from the server. In order for the RPC to " + "successfully return data, the server component must be available.</p>" + "<p>If you are running this demo from compiled code, the server " + "component may not be available to respond to the RPC requests from " + "DynaTable. Try running DynaTable in development mode to see the demo " + "in action.</p> " + "<p>Click on the Remote Procedure Call link above for more information " + "on GWT's RPC infrastructure."; private final RowDataAcceptor acceptor = new RowDataAcceptorImpl(); private final Grid grid = new Grid(); private final NavBar navbar = new NavBar(); private ErrorDialog errorDialog = null; private final DockPanel outer = new DockPanel(); private final DynaTableDataProvider provider; private int startRow = 0; public DynaTableWidget(DynaTableDataProvider provider, String[] columns, String[] columnStyles, int rowCount) { if (columns.length == 0) { throw new IllegalArgumentException( "expecting a positive number of columns"); } if (columnStyles != null && columns.length != columnStyles.length) { throw new IllegalArgumentException("expecting as many styles as columns"); } this.provider = provider; initWidget(outer); grid.setStyleName("table"); outer.add(navbar, DockPanel.NORTH); outer.add(grid, DockPanel.CENTER); initTable(columns, columnStyles, rowCount); setStyleName("DynaTable-DynaTableWidget"); } public void clearStatusText() { navbar.status.setHTML(" "); } public void refresh() { // Disable buttons temporarily to stop the user from running off the end. // navbar.gotoFirst.setEnabled(false); navbar.gotoPrev.setEnabled(false); navbar.gotoNext.setEnabled(false); setStatusText("Please wait..."); provider.updateRowData(startRow, grid.getRowCount() - 1, acceptor); } public void setRowCount(int rows) { grid.resizeRows(rows); } public void setStatusText(String text) { navbar.status.setText(text); } private int getDataRowCount() { return grid.getRowCount() - 1; } private void initTable(String[] columns, String[] columnStyles, int rowCount) { // Set up the header row. It's one greater than the number of visible rows. // grid.resize(rowCount + 1, columns.length); for (int i = 0, n = columns.length; i < n; i++) { grid.setText(0, i, columns[i]); if (columnStyles != null) { grid.getCellFormatter().setStyleName(0, i, columnStyles[i] + " header"); } } } }