001package gwt.material.design.client.ui; 002/* 003 * #%L 004 * GwtMaterial 005 * %% 006 * Copyright (C) 2015 GwtMaterialDesign 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * #L% 020 */ 021 022import com.google.gwt.core.client.Scheduler; 023import com.google.gwt.dom.client.Document; 024import com.google.gwt.event.dom.client.ClickEvent; 025import com.google.gwt.event.dom.client.ClickHandler; 026import com.google.gwt.user.client.Command; 027import com.google.gwt.user.client.Event; 028import gwt.material.design.client.base.MaterialWidget; 029import gwt.material.design.client.constants.IconPosition; 030import gwt.material.design.client.constants.IconType; 031import gwt.material.design.client.constants.WavesType; 032import gwt.material.design.client.events.PageSelectionEvent; 033import gwt.material.design.client.ui.html.ListItem; 034 035import static gwt.material.design.client.events.PageSelectionEvent.PageSelectionHandler; 036import static gwt.material.design.client.events.PageSelectionEvent.TYPE; 037 038//@formatter:off 039 040/** 041 * Material Pager with page event 042 * <h3>UiBinder Usage:</h3> 043 * <pre> 044 * {@code<m:MaterialPager ui:field='pager' />} 045 * </pre> 046 * 047 * @author Guaido79 048 */ 049public class MaterialPager extends MaterialWidget { 050 051 private int total; 052 private int pageSize = 10; 053 private int currentPage = 1; 054 private int maxPageLinksShown = 10; 055 private boolean enableIndicator; 056 private String indicatorTemplate = "Page {page} of {total}"; 057 058 private int calcTotalPages; 059 private int calcShowingPageFrom; 060 private int calcShowingPageTo; 061 private boolean calcInitialized; 062 063 private PagerListItem linkLeft; 064 private PagerListItem linkRight; 065 066 private MaterialChip indicator; 067 068 public MaterialPager() { 069 super(Document.get().createULElement(), "pagination"); 070 setWaves(WavesType.DEFAULT); 071 removeStyleName("waves-effect"); 072 } 073 074 public MaterialPager(int total, int pageSize) { 075 this(); 076 this.total = total; 077 this.pageSize = pageSize; 078 } 079 080 public MaterialPager(int total, int pageSize, int currentPage) { 081 this(total, pageSize); 082 this.currentPage = currentPage; 083 } 084 085 @Override 086 protected void onLoad() { 087 super.onLoad(); 088 init(); 089 } 090 091 private void init() { 092 if (!calcInitialized) { 093 calcTotalPages = total / pageSize + (((double) total % (double) pageSize) > 0 ? 1 : 0); 094 095 add(getOrCreateLiElementLeft()); 096 moveNextPagesRange(); 097 add(getOrCreateLiElementRight()); 098 if (enableIndicator) { 099 add(createLiElementIndicator()); 100 } 101 onPageSelection(1); 102 103 calcInitialized = true; 104 } 105 } 106 107 protected void moveNextPagesRange() { 108 calcShowingPageFrom = currentPage; 109 calcShowingPageTo = Math.min(currentPage + maxPageLinksShown - 1, calcTotalPages); 110 createPageNumberLinks(); 111 } 112 113 protected void movePreviousPagesRange() { 114 calcShowingPageFrom = currentPage - maxPageLinksShown + 1; 115 calcShowingPageTo = currentPage; 116 createPageNumberLinks(); 117 } 118 119 protected void createPageNumberLinks() { 120 121 for (int i = 0; i < getWidgetCount(); i++) { 122 final PagerListItem widget = (PagerListItem) getWidget(i); 123 if (!widget.isFixed()) { 124 Scheduler.get().scheduleDeferred(new Command() { 125 @Override 126 public void execute() { 127 widget.removeFromParent(); 128 } 129 }); 130 } 131 } 132 int insertionIndex = 1; 133 for (int i = calcShowingPageFrom; i <= calcShowingPageTo; i++) { 134 final PagerListItem liElementForPage = createLiElementForPage(i); 135 136 Scheduler.get().scheduleDeferred(new InsertElementAtPositionCommand(insertionIndex++) { 137 @Override 138 public void execute() { 139 insert(liElementForPage, insertionIndex); 140 } 141 }); 142 143 } 144 } 145 146 protected PagerListItem createLiElementForPage(final int page) { 147 final PagerListItem pageLiElement = new PagerListItem(); 148 pageLiElement.setFixed(false); 149 pageLiElement.add(createLinkPage(page)); 150 151 addPageSelectionHandler(new PageSelectionHandler() { 152 @Override 153 public void onPageSelected(PageSelectionEvent event) { 154 pageLiElement.setActive(event.getPageTo() == page); 155 } 156 }); 157 158 pageLiElement.addHandler(new ClickHandler() { 159 @Override 160 public void onClick(ClickEvent event) { 161 onPageSelection(page); 162 event.preventDefault(); 163 event.stopPropagation(); 164 } 165 }, ClickEvent.getType()); 166 167 return pageLiElement; 168 } 169 170 protected PagerListItem getOrCreateLiElementLeft() { 171 linkLeft = new PagerListItem(); 172 linkLeft.setFixed(true); 173 MaterialLink mLink = createLinkLeft(); 174 linkLeft.addHandler(new ClickHandler() { 175 @Override 176 public void onClick(ClickEvent event) { 177 if (linkLeft.isEnabled()) 178 onPageSelection(currentPage - 1); 179 event.preventDefault(); 180 event.stopPropagation(); 181 } 182 }, ClickEvent.getType()); 183 this.linkLeft.add(mLink); 184 185 addPageSelectionHandler(new PageSelectionHandler() { 186 @Override 187 public void onPageSelected(PageSelectionEvent event) { 188 MaterialPager.this.linkLeft.setEnabled(event.getPageTo() > 1); 189 } 190 }); 191 192 return this.linkLeft; 193 } 194 195 protected PagerListItem getOrCreateLiElementRight() { 196 linkRight = new PagerListItem(); 197 linkRight.setFixed(true); 198 MaterialLink mLink = createLinkRight(); 199 linkRight.addHandler(new ClickHandler() { 200 @Override 201 public void onClick(ClickEvent event) { 202 if (linkRight.isEnabled()) 203 onPageSelection(currentPage + 1); 204 event.stopPropagation(); 205 event.preventDefault(); 206 } 207 }, ClickEvent.getType()); 208 this.linkRight.add(mLink); 209 210 addPageSelectionHandler(new PageSelectionHandler() { 211 @Override 212 public void onPageSelected(PageSelectionEvent event) { 213 MaterialPager.this.linkRight.setEnabled(event.getPageTo() < calcTotalPages); 214 } 215 }); 216 217 return this.linkRight; 218 } 219 220 protected PagerListItem createLiElementIndicator() { 221 222 PagerListItem indicatorLi = new PagerListItem(false); 223 indicatorLi.setFixed(true); 224 indicatorLi.add(getOrCreateIndicator()); 225 return indicatorLi; 226 } 227 228 protected MaterialChip getOrCreateIndicator() { 229 indicator = new MaterialChip(); 230 indicator.getElement().getStyle().setBackgroundColor("inherit"); 231 addPageSelectionHandler(new PageSelectionHandler() { 232 @Override 233 public void onPageSelected(PageSelectionEvent event) { 234 indicator.setText( 235 indicatorTemplate 236 .replaceAll("\\{page\\}", String.valueOf(event.getPageTo())) 237 .replaceAll("\\{total\\}", String.valueOf(event.getTotalPage())) 238 ); 239 } 240 }); 241 242 return indicator; 243 } 244 245 protected MaterialLink createLinkPage(final int page) { 246 MaterialLink link = new MaterialLink(String.valueOf(page)); 247 248 return link; 249 } 250 251 protected MaterialLink createLinkLeft() { 252 final MaterialLink linkLeft = new MaterialLink(IconType.CHEVRON_LEFT); 253 linkLeft.setIconPosition(IconPosition.NONE); 254 return linkLeft; 255 } 256 257 protected MaterialLink createLinkRight() { 258 final MaterialLink linkRight = new MaterialLink(IconType.CHEVRON_RIGHT); 259 linkRight.setIconPosition(IconPosition.NONE); 260 return linkRight; 261 } 262 263 protected void onPageSelection(int page) { 264 this.currentPage = page; 265 266 if (this.currentPage > calcShowingPageTo) { 267 moveNextPagesRange(); 268 } 269 if (this.currentPage < calcShowingPageFrom) { 270 movePreviousPagesRange(); 271 } 272 273 PageSelectionEvent event = new PageSelectionEvent(); 274 event.setPageFrom(this.currentPage); 275 event.setPageTo(page); 276 event.setTotalPage(this.calcTotalPages); 277 278 fireEvent(event); 279 } 280 281 public void addPageSelectionHandler(PageSelectionHandler handler) { 282 this.addHandler(handler, TYPE); 283 } 284 285 public boolean isEnableIndicator() { 286 return enableIndicator; 287 } 288 289 public void setEnableIndicator(boolean enableIndicator) { 290 this.enableIndicator = enableIndicator; 291 } 292 293 public int getTotal() { 294 return total; 295 } 296 297 public void setTotal(final int total) { 298 boolean needToClear = total != this.total; 299 this.total = total; 300 currentPage = 1; 301 if (calcInitialized && needToClear) { 302 this.clear(); 303 init(); 304 } 305 } 306 307 public int getPageSize() { 308 return pageSize; 309 } 310 311 public void setPageSize(int pageSize) { 312 this.pageSize = pageSize; 313 } 314 315 public int getCurrentPage() { 316 return currentPage; 317 } 318 319 public void setCurrentPage(int currentPage) { 320 this.currentPage = currentPage; 321 } 322 323 public int getMaxPageLinksShown() { 324 return maxPageLinksShown; 325 } 326 327 public void setMaxPageLinksShown(int maxPageLinksShown) { 328 this.maxPageLinksShown = maxPageLinksShown; 329 } 330 331 public String getIndicatorTemplate() { 332 return indicatorTemplate; 333 } 334 335 /** 336 * Set the paging indicator label with a custom template 337 * <ul> 338 * <li><strong>{page}</strong> is the current page</li> 339 * <li><strong>{total}</strong> is the total page</li> 340 * </ul> 341 * Example 342 * <pre> 343 *{@code 344 * Page {page} of {total} 345 * }</pre> 346 * 347 * @param indicatorTemplate 348 */ 349 public void setIndicatorTemplate(String indicatorTemplate) { 350 this.indicatorTemplate = indicatorTemplate; 351 } 352 353 static abstract class InsertElementAtPositionCommand implements Scheduler.ScheduledCommand { 354 protected int insertionIndex; 355 356 InsertElementAtPositionCommand(int insertionIndex) { 357 this.insertionIndex = insertionIndex; 358 } 359 } 360 361 static class PagerListItem extends ListItem { 362 363 private boolean fixed; 364 private boolean enabled; 365 366 public PagerListItem() { 367 this(true); 368 } 369 370 public PagerListItem(boolean clickable) { 371 if (clickable) { 372 addStyleName("waves-effect"); 373 sinkEvents(Event.ONCLICK | Event.TOUCHEVENTS); 374 } 375 } 376 377 public boolean isFixed() { 378 return fixed; 379 } 380 381 public void setFixed(boolean fixed) { 382 this.fixed = fixed; 383 } 384 385 public void setActive(boolean active) { 386 if (active) { 387 addStyleName("active"); 388 } else { 389 removeStyleName("active"); 390 } 391 } 392 393 @Override 394 public boolean isEnabled() { 395 return enabled; 396 } 397 398 @Override 399 public void setEnabled(boolean enabled) { 400 this.enabled = enabled; 401 if (!enabled) { 402 addStyleName("disabled"); 403 } else { 404 removeStyleName("disabled"); 405 } 406 } 407 } 408}