RelatedListTable: Make sure that the tableName is set.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / client / ui / details / RelatedListTable.java
1 /*
2  * Copyright (C) 2011 Openismus GmbH
3  *
4  * This file is part of GWT-Glom.
5  *
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.
10  *
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
14  * for more details.
15  *
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/>.
18  */
19
20 package org.glom.web.client.ui.details;
21
22 import java.util.ArrayList;
23
24 import org.glom.web.client.OnlineGlomServiceAsync;
25 import org.glom.web.client.ui.OnlineGlomConstants;
26 import org.glom.web.client.ui.cell.NavigationButtonCell;
27 import org.glom.web.client.ui.list.ListTable;
28 import org.glom.web.shared.DataItem;
29 import org.glom.web.shared.TypedDataItem;
30 import org.glom.web.shared.libglom.layout.LayoutItemPortal;
31
32 import com.google.gwt.core.client.GWT;
33 import com.google.gwt.dom.client.Document;
34 import com.google.gwt.dom.client.Style.Visibility;
35 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
36 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
37 import com.google.gwt.user.cellview.client.Column;
38 import com.google.gwt.user.cellview.client.ColumnSortList;
39 import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
40 import com.google.gwt.user.cellview.client.SimplePager;
41 import com.google.gwt.user.client.rpc.AsyncCallback;
42 import com.google.gwt.user.client.ui.FlowPanel;
43 import com.google.gwt.user.client.ui.HTML;
44 import com.google.gwt.view.client.AsyncDataProvider;
45 import com.google.gwt.view.client.HasData;
46 import com.google.gwt.view.client.Range;
47 import com.google.gwt.view.client.RowCountChangeEvent;
48
49 /**
50  *
51  */
52 public class RelatedListTable extends ListTable {
53
54         // OnlineGlomConstants.java is generated in the target/ directory,
55         // from OnlineGlomConstants.properties
56         // by the gwt-maven-plugin's i18n (mvn:i18n) goal.
57         private OnlineGlomConstants constants = GWT.create(OnlineGlomConstants.class);
58
59         // These represent the minimum and maximum number of rows in the cell table not the number of rows with data.
60         private static final int MAX_TABLE_ROWS = 5;
61         private static final int MIN_TABLE_ROWS = MAX_TABLE_ROWS;
62
63         private TypedDataItem foreignKeyValue;
64         private String relationshipName;
65         private int numNonEmptyRows = 0;
66
67         private final static int expectedHeight = initializeExepectedHeight();
68
69         public RelatedListTable(String documentID, String tableName, LayoutItemPortal layoutItemPortal, TypedDataItem foreignKeyValue,
70                         NavigationButtonCell navigationButtonCell) {
71
72                 super(documentID);
73                 super.tableName = tableName;
74
75                 // These variables need to be set before the createCellTable() method is called so that the data provider can
76                 // use them.
77                 this.foreignKeyValue = foreignKeyValue;
78                 this.relationshipName = layoutItemPortal.getRelationshipNameUsed();
79
80                 // TODO: Is tableName set here?
81                 createCellTable(layoutItemPortal, tableName, MAX_TABLE_ROWS, constants.open(), navigationButtonCell);
82
83                 // The FixedLayout property tells the browser that we want to manually specify the column widths and don't want
84                 // the table to overflow it's container. Browsers will make columns with equal widths since we're currently not
85                 // manally specifying the column widths.
86                 cellTable.setWidth("100%", true);
87
88         }
89
90         /*
91          * (non-Javadoc)
92          * 
93          * @see org.glom.web.client.ui.list.ListTable#getDataProvider()
94          */
95         @Override
96         protected AsyncDataProvider<DataItem[]> getDataProvider() {
97                 AsyncDataProvider<DataItem[]> dataProvider = new AsyncDataProvider<DataItem[]>() {
98
99                         @Override
100                         @SuppressWarnings("unchecked")
101                         protected void onRangeChanged(final HasData<DataItem[]> display) {
102                                 // setup the callback object
103                                 final Range range = display.getVisibleRange();
104                                 final int start = range.getStart();
105                                 AsyncCallback<ArrayList<DataItem[]>> callback = new AsyncCallback<ArrayList<DataItem[]>>() {
106                                         @Override
107                                         public void onFailure(Throwable caught) {
108                                                 // TODO: create a way to notify users of asynchronous callback failures
109                                                 GWT.log("AsyncCallback Failed: OnlineGlomService.get(Sorted)RelatedListData(): "
110                                                                 + caught.getMessage());
111                                         }
112
113                                         @Override
114                                         public void onSuccess(ArrayList<DataItem[]> result) {
115                                                 // keep track of the number of non-empty rows (rows with data)
116                                                 numNonEmptyRows = 0;
117                                                 if(result != null) {
118                                                         numNonEmptyRows = result.size();
119                                                 }
120
121                                                 // Add empty rows if required.
122                                                 int numEmptyRows = MIN_TABLE_ROWS - numNonEmptyRows;
123                                                 for (int i = 0; i < numEmptyRows; i++) {
124                                                         // A row that has one null item will be rendered as an empty row.
125                                                         result.add(new DataItem[1]);
126                                                 }
127                                                 updateRowData(start, result);
128
129                                                 // Note: numNonEmptyRows is not used by the RowCountChangeEvent handler but we need to fire the
130                                                 // event to get ListTable.ListTablePage.createText() to run and update the pager text using
131                                                 // getNumNonEmptyRows().
132                                                 RowCountChangeEvent.fire(display, numNonEmptyRows, true);
133                                         }
134                                 };
135
136                                 // get data from the server
137                                 ColumnSortList colSortList = cellTable.getColumnSortList();
138                                 if (colSortList.size() > 0) {
139                                         // ColumnSortEvent has been requested by the user
140                                         ColumnSortInfo info = colSortList.get(0);
141
142                                         OnlineGlomServiceAsync.Util.getInstance().getSortedRelatedListData(documentID, tableName,
143                                                         relationshipName, foreignKeyValue, start, range.getLength(),
144                                                         cellTable.getColumnIndex((Column<DataItem[], ?>) info.getColumn()), info.isAscending(),
145                                                         callback);
146
147                                 } else {
148                                         OnlineGlomServiceAsync.Util.getInstance().getRelatedListData(documentID, tableName,
149                                                         relationshipName, foreignKeyValue, start, range.getLength(), callback);
150
151                                 }
152
153                         }
154                 };
155
156                 return dataProvider;
157         }
158
159         /*
160          * (non-Javadoc)
161          * 
162          * @see org.glom.web.client.ui.list.ListTable#getMinNumVisibleRows()
163          */
164         @Override
165         public int getMinNumVisibleRows() {
166                 return MIN_TABLE_ROWS;
167         }
168
169         /*
170          * (non-Javadoc)
171          * 
172          * @see org.glom.web.client.ui.list.ListTable#getNumNonEmptyRows()
173          */
174         @Override
175         public int getNumNonEmptyRows() {
176                 return numNonEmptyRows;
177         }
178
179         /**
180          * Gets the expected height of a RelatedListTable.
181          * 
182          * @return the expect height of a RelatedListTable in pixels
183          */
184         public static int getExpectedHeight() {
185                 return expectedHeight;
186         }
187
188         // called while class is being initialized
189         private static int initializeExepectedHeight() {
190                 // TODO Use a real RelatedListTable instead of building one manually. It's probably better to do this when
191                 // RelatedListTables are created in Portal instead of DetailsActivity.
192
193                 // This table simulates a related list with one row containing a Text cell and a Button cell.
194                 SafeHtmlBuilder tableBuilder = new SafeHtmlBuilder();
195                 tableBuilder.append(SafeHtmlUtils
196                                 .fromSafeConstant("<table class=\"data-list\"><thead><tr><th>TH</th><th>BH</th></tr></thead><tbody>"));
197                 for (int i = 0; i < MAX_TABLE_ROWS; i++) {
198                         tableBuilder.append(SafeHtmlUtils
199                                         .fromSafeConstant("<tr><td>T</td><td><button type=\"button\">B</button></td></tr>"));
200                 }
201                 tableBuilder.append(SafeHtmlUtils.fromSafeConstant("</tbody></head>"));
202                 HTML table = new HTML(tableBuilder.toSafeHtml());
203
204                 // The pager
205                 SimplePager pager = new SimplePager();
206                 pager.addStyleName("pager");
207
208                 // Pack the table and pager as they are found in the details view.
209                 FlowPanel group = new FlowPanel();
210                 group.setStyleName("group");
211                 FlowPanel subgroup = new FlowPanel();
212                 subgroup.setStyleName("portal");
213                 subgroup.add(table);
214                 subgroup.add(pager);
215                 group.add(subgroup);
216
217                 // Calculate the height similar to Utils.getWidgetHeight().
218                 Document doc = Document.get();
219                 com.google.gwt.dom.client.Element div = doc.createDivElement();
220                 div.getStyle().setVisibility(Visibility.HIDDEN);
221                 div.appendChild(group.getElement().<com.google.gwt.user.client.Element> cast());
222                 doc.getBody().appendChild(div);
223                 int relatedListTableHeight = group.getElement().getFirstChildElement().getOffsetHeight();
224
225                 // remove the div from the from the document
226                 doc.getBody().removeChild(div);
227                 div = null;
228
229                 return relatedListTableHeight;
230         }
231 }