001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2016 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.client.ui.pager; 021 022import com.google.gwt.core.client.GWT; 023import com.google.gwt.dom.client.Document; 024import gwt.material.design.client.base.MaterialWidget; 025import gwt.material.design.client.base.constants.TableCssName; 026import gwt.material.design.client.data.DataSource; 027import gwt.material.design.client.data.loader.LoadCallback; 028import gwt.material.design.client.data.loader.LoadConfig; 029import gwt.material.design.client.data.loader.LoadResult; 030import gwt.material.design.client.ui.MaterialToast; 031import gwt.material.design.client.ui.table.MaterialDataTable; 032 033/** 034 * Material Data Pager - a simple pager for Material Data Table component 035 * 036 * @author kevzlou7979 037 */ 038public class MaterialDataPager<T> extends MaterialWidget implements HasPager { 039 040 private MaterialDataTable<T> table; 041 private DataSource<T> dataSource; 042 043 private int offset = 0; 044 private int limit = 0; 045 private int currentPage = 1; 046 private int totalRows = 0; 047 private int[] limitOptions = new int[]{5, 10, 20}; 048 049 private PageActionsPanel actionsPanel = new PageActionsPanel(this); 050 private PageNumberSelection pageNumberSelection = new PageNumberSelection(this); 051 private PageRowSelection pageRowSelection = new PageRowSelection(this); 052 053 public MaterialDataPager() { 054 super(Document.get().createDivElement(), TableCssName.DATA_PAGER, TableCssName.ROW); 055 } 056 057 public MaterialDataPager(MaterialDataTable<T> table, DataSource<T> dataSource) { 058 this(); 059 this.table = table; 060 this.dataSource = dataSource; 061 } 062 063 /** 064 * Initialize the data pager for navigation 065 */ 066 @Override 067 protected void onLoad() { 068 super.onLoad(); 069 070 limit = limitOptions[0]; 071 072 add(pageNumberSelection); 073 add(pageRowSelection); 074 add(actionsPanel); 075 076 firstPage(); 077 } 078 079 public void updateRowsPerPage(int limit) { 080 if ((totalRows / currentPage) < limit) { 081 lastPage(); 082 return; 083 } 084 gotoPage(pageNumberSelection.getValue()); 085 } 086 087 @Override 088 public void next() { 089 currentPage++; 090 gotoPage(currentPage); 091 } 092 093 @Override 094 public void previous() { 095 currentPage--; 096 gotoPage(currentPage); 097 } 098 099 @Override 100 public void lastPage() { 101 if (isExcess()) { 102 gotoPage((totalRows / limit) + 1); 103 }else { 104 gotoPage(totalRows / limit); 105 } 106 107 pageNumberSelection.setSelectedIndex(currentPage - 1); 108 } 109 110 @Override 111 public void firstPage() { 112 gotoPage(1); 113 } 114 115 @Override 116 public void gotoPage(int page) { 117 this.currentPage = page; 118 doLoad((page * limit) - limit, limit); 119 } 120 121 @Override 122 public int getCurrentPage() { 123 return currentPage; 124 } 125 126 @Override 127 public void setLimit(int limit) { 128 this.limit = limit; 129 } 130 131 @Override 132 public boolean isNext() { 133 return offset + limit < totalRows; 134 } 135 136 @Override 137 public boolean isPrevious() { 138 return offset - limit >= 0; 139 } 140 141 /** 142 * Set the limit as an array of options to be populated inside the rows per page listbox 143 */ 144 public void setLimitOptions(int... limitOptions) { 145 this.limitOptions = limitOptions; 146 } 147 148 /** 149 * Check whether there are excess rows to be rendered with given limit 150 */ 151 public boolean isExcess() { 152 return totalRows % limit > 0; 153 } 154 155 /** 156 * Check whether the pager is on the last currentPage. 157 */ 158 public boolean isLastPage() { 159 return currentPage == (totalRows / limit) + 1; 160 } 161 162 /** 163 * Load the datasource within a given offset and limit 164 */ 165 protected void doLoad(int offset, int limit) { 166 this.offset = offset; 167 168 // Check whether the pager has excess rows with given limit 169 if (isLastPage() & isExcess()) { 170 // Get the difference between total rows and excess rows 171 limit = totalRows - offset; 172 } 173 174 int finalLimit = limit; 175 dataSource.load(new LoadConfig<>(offset, limit, table.getView().getSortContext(), 176 table.getView().getOpenCategories()), new LoadCallback<T>() { 177 @Override 178 public void onSuccess(LoadResult<T> loadResult) { 179 totalRows = loadResult.getTotalLength(); 180 table.setVisibleRange(offset, finalLimit); 181 table.loaded(loadResult.getOffset(), loadResult.getData()); 182 updateUi(); 183 } 184 185 @Override 186 public void onFailure(Throwable caught) { 187 GWT.log("Load failure", caught); 188 //TODO: What we need to do on failure? May be clear table? 189 } 190 }); 191 } 192 193 /** 194 * Set and update the ui fields of the pager after the datasource load callback 195 */ 196 protected void updateUi() { 197 pageNumberSelection.updatePageNumber(totalRows, limit, currentPage); 198 199 // Action label (current selection) in either the form "x-y of z" or "y of z" (when page has only 1 record) 200 int firstRow = offset + 1; 201 int lastRow = (isExcess() & isLastPage()) ? totalRows : (offset + limit); 202 actionsPanel.getActionLabel().setText((firstRow == lastRow ? lastRow : firstRow + "-" + lastRow) + " of " + totalRows); 203 204 actionsPanel.getIconNext().setEnabled(true); 205 actionsPanel.getIconPrev().setEnabled(true); 206 207 if (!isNext()) { 208 actionsPanel.getIconNext().setEnabled(false); 209 } 210 211 if (!isPrevious()) { 212 actionsPanel.getIconPrev().setEnabled(false); 213 } 214 } 215 216 public MaterialDataTable<T> getTable() { 217 return table; 218 } 219 220 public void setTable(MaterialDataTable<T> table) { 221 this.table = table; 222 } 223 224 public DataSource<T> getDataSource() { 225 return dataSource; 226 } 227 228 public void setDataSource(DataSource<T> dataSource) { 229 this.dataSource = dataSource; 230 } 231 232 public int getOffset() { 233 return offset; 234 } 235 236 public int getLimit() { 237 return limit; 238 } 239 240 public int getTotalRows() { 241 return totalRows; 242 } 243 244 public int[] getLimitOptions() { 245 return limitOptions; 246 } 247}