001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 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.table; 021 022import com.google.gwt.cell.client.Cell; 023import com.google.gwt.cell.client.Cell.Context; 024import com.google.gwt.cell.client.FieldUpdater; 025import com.google.gwt.cell.client.HasCell; 026import com.google.gwt.cell.client.ValueUpdater; 027import com.google.gwt.dom.client.BrowserEvents; 028import com.google.gwt.dom.client.Element; 029import com.google.gwt.dom.client.EventTarget; 030import com.google.gwt.dom.client.TableCellElement; 031import com.google.gwt.dom.client.TableRowElement; 032import com.google.gwt.event.shared.HandlerRegistration; 033import com.google.gwt.user.client.DOM; 034import com.google.gwt.user.client.Event; 035import com.google.gwt.view.client.Range; 036import gwt.material.design.client.base.constants.TableCssName; 037import gwt.material.design.client.data.DataSource; 038import gwt.material.design.client.data.Renderer; 039import gwt.material.design.client.data.SelectionType; 040import gwt.material.design.client.data.SortDir; 041import gwt.material.design.client.data.component.CategoryComponent; 042import gwt.material.design.client.data.component.ComponentFactory; 043import gwt.material.design.client.data.component.RowComponent; 044import gwt.material.design.client.data.events.CategoryClosedEvent; 045import gwt.material.design.client.data.events.CategoryClosedHandler; 046import gwt.material.design.client.data.events.CategoryOpenedEvent; 047import gwt.material.design.client.data.events.CategoryOpenedHandler; 048import gwt.material.design.client.data.events.ColumnSortEvent; 049import gwt.material.design.client.data.events.ColumnSortHandler; 050import gwt.material.design.client.data.events.ComponentsRenderedEvent; 051import gwt.material.design.client.data.events.ComponentsRenderedHandler; 052import gwt.material.design.client.data.events.DestroyEvent; 053import gwt.material.design.client.data.events.DestroyHandler; 054import gwt.material.design.client.data.events.InsertColumnEvent; 055import gwt.material.design.client.data.events.InsertColumnHandler; 056import gwt.material.design.client.data.events.RemoveColumnEvent; 057import gwt.material.design.client.data.events.RemoveColumnHandler; 058import gwt.material.design.client.data.events.RenderedEvent; 059import gwt.material.design.client.data.events.RenderedHandler; 060import gwt.material.design.client.data.events.RowCollapsedEvent; 061import gwt.material.design.client.data.events.RowCollapsedHandler; 062import gwt.material.design.client.data.events.RowCollapsingEvent; 063import gwt.material.design.client.data.events.RowCollapsingHandler; 064import gwt.material.design.client.data.events.RowContextMenuEvent; 065import gwt.material.design.client.data.events.RowContextMenuHandler; 066import gwt.material.design.client.data.events.RowDoubleClickEvent; 067import gwt.material.design.client.data.events.RowDoubleClickHandler; 068import gwt.material.design.client.data.events.RowExpandedEvent; 069import gwt.material.design.client.data.events.RowExpandedHandler; 070import gwt.material.design.client.data.events.RowExpandingEvent; 071import gwt.material.design.client.data.events.RowExpandingHandler; 072import gwt.material.design.client.data.events.RowLongPressEvent; 073import gwt.material.design.client.data.events.RowLongPressHandler; 074import gwt.material.design.client.data.events.RowSelectEvent; 075import gwt.material.design.client.data.events.RowSelectHandler; 076import gwt.material.design.client.data.events.RowShortPressEvent; 077import gwt.material.design.client.data.events.RowShortPressHandler; 078import gwt.material.design.client.data.events.SelectAllEvent; 079import gwt.material.design.client.data.events.SelectAllHandler; 080import gwt.material.design.client.data.events.SetupEvent; 081import gwt.material.design.client.data.events.SetupHandler; 082import gwt.material.design.client.data.factory.RowComponentFactory; 083import gwt.material.design.client.events.DefaultHandlerRegistry; 084import gwt.material.design.client.events.HandlerRegistry; 085import gwt.material.design.client.base.MaterialWidget; 086import gwt.material.design.client.data.DataView; 087import gwt.material.design.client.data.StandardDataView; 088import gwt.material.design.client.ui.table.cell.Column; 089 090import java.util.List; 091import java.util.Set; 092import java.util.logging.Level; 093import java.util.logging.Logger; 094 095/** 096 * An abstract data table implementation that can be attached to the DOM. 097 * The core functionality is based on the registered {@link DataView}, 098 * this will handle scaffolding, event registration, and attachment. 099 * 100 * @author Ben Dol 101 */ 102public abstract class AbstractDataTable<T> extends MaterialWidget implements DataDisplay<T> { 103 104 private static final Logger logger = Logger.getLogger(AbstractDataTable.class.getName()); 105 106 public static class DefaultTableScaffolding extends TableScaffolding { 107 @Override 108 public MaterialWidget createTableBody() { 109 MaterialWidget tableBody = new MaterialWidget(DOM.createDiv()); 110 tableBody.addStyleName(TableCssName.TABLE_BODY); 111 return tableBody; 112 } 113 114 @Override 115 public MaterialWidget createTopPanel() { 116 MaterialWidget topPanel = new MaterialWidget(DOM.createDiv()); 117 topPanel.addStyleName(TableCssName.TOP_PANEL); 118 return topPanel; 119 } 120 121 @Override 122 public MaterialWidget createInfoPanel() { 123 MaterialWidget infoPanel = new MaterialWidget(DOM.createDiv()); 124 infoPanel.addStyleName(TableCssName.INFO_PANEL); 125 return infoPanel; 126 } 127 128 @Override 129 public MaterialWidget createToolPanel() { 130 MaterialWidget toolPanel = new MaterialWidget(DOM.createDiv()); 131 toolPanel.addStyleName(TableCssName.TOOL_PANEL); 132 return toolPanel; 133 } 134 135 @Override 136 protected Table createTable() { 137 Table table = new Table(); 138 table.addStyleName(TableCssName.TABLE); 139 return table; 140 } 141 } 142 143 protected DataView<T> view; 144 protected TableScaffolding scaffolding; 145 protected HandlerRegistry handlerRegistry; 146 147 private boolean focused; 148 private boolean refreshing; 149 private boolean cellIsEditing; 150 private boolean destroyOnUnload; 151 152 private HandlerRegistration setupHandler; 153 154 public AbstractDataTable() { 155 this(new StandardDataView<>()); 156 } 157 158 public AbstractDataTable(DataView<T> view) { 159 this(view, new DefaultTableScaffolding()); 160 } 161 162 public AbstractDataTable(TableScaffolding scaffolding) { 163 this(); 164 this.scaffolding = scaffolding; 165 } 166 167 public AbstractDataTable(DataView<T> view, TableScaffolding scaffolding) { 168 super(DOM.createElement("section")); 169 this.view = view; 170 this.scaffolding = scaffolding; 171 172 view.setDisplay(this); 173 setStyleName("table-container"); 174 175 handlerRegistry = new DefaultHandlerRegistry(this); 176 177 // Build the table scaffolding 178 scaffolding.build(); 179 scaffolding.apply(this); 180 181 // Apply the DOM build. 182 build(); 183 } 184 185 @Override 186 protected void onLoad() { 187 super.onLoad(); 188 189 if(!view.isSetup()) { 190 try { 191 view.setup(scaffolding); 192 } catch (Exception ex) { 193 logger.log(Level.SEVERE, 194 "Could not setup AbstractDataTable due to previous errors.", ex); 195 } 196 // We should recalculate when we load again. 197 } else if(view.isUseCategories()) { 198 view.getSubheaderLib().recalculate(true); 199 } 200 } 201 202 @Override 203 protected void onUnload() { 204 super.onUnload(); 205 206 clearHandlers(); 207 208 if(destroyOnUnload) { 209 view.destroy(); 210 } 211 } 212 213 protected void build() { 214 // Nothing by default. 215 } 216 217 @Override 218 public final DataView<T> getView() { 219 return view; 220 } 221 222 @Override 223 public final Range getVisibleRange() { 224 return view.getVisibleRange(); 225 } 226 227 @Override 228 public final void setVisibleRange(int start, int length) { 229 view.setVisibleRange(start, length); 230 } 231 232 @Override 233 public final void setVisibleRange(Range range) { 234 view.setVisibleRange(range); 235 } 236 237 @Override 238 public final int getRowCount() { 239 return view.getRowCount(); 240 } 241 242 @Override 243 public final void setRowData(int start, List<? extends T> values) { 244 view.setRowData(start, values); 245 } 246 247 @Override 248 public final void setCategoryFactory(ComponentFactory<? extends CategoryComponent, String> categoryFactory) { 249 view.setCategoryFactory(categoryFactory); 250 } 251 252 @Override 253 public final CategoryComponent getCategory(String categoryName) { 254 return view.getCategory(categoryName); 255 } 256 257 @Override 258 public final List<CategoryComponent> getCategories() { 259 return view.getCategories(); 260 } 261 262 @Override 263 public final List<CategoryComponent> getOpenCategories() { 264 return view.getOpenCategories(); 265 } 266 267 @Override 268 public final boolean isCategoryEmpty(CategoryComponent category) { 269 return view.isCategoryEmpty(category); 270 } 271 272 @Override 273 public final void addCategory(String category) { 274 view.addCategory(category); 275 } 276 277 @Override 278 public final void addCategory(CategoryComponent category) { 279 view.addCategory(category); 280 } 281 282 @Override 283 public final boolean hasCategory(String categoryName) { 284 return view.hasCategory(categoryName); 285 } 286 287 @Override 288 public final void disableCategory(String categoryName) { 289 view.disableCategory(categoryName); 290 } 291 292 @Override 293 public final void enableCategory(String categoryName) { 294 view.enableCategory(categoryName); 295 } 296 297 @Override 298 public final void openCategory(String categoryName) { 299 view.openCategory(categoryName); 300 } 301 302 @Override 303 public final void openCategory(CategoryComponent category) { 304 view.openCategory(category); 305 } 306 307 @Override 308 public final void closeCategory(String categoryName) { 309 view.closeCategory(categoryName); 310 } 311 312 @Override 313 public final void closeCategory(CategoryComponent category) { 314 view.closeCategory(category); 315 } 316 317 @Override 318 public final void clearRowsAndCategories(boolean clearData) { 319 view.clearRowsAndCategories(clearData); 320 } 321 322 @Override 323 public final void clearCategories() { 324 view.clearCategories(); 325 } 326 327 @Override 328 public final void addColumn(Column<T, ?> column) { 329 view.addColumn(column); 330 } 331 332 @Override 333 public final void addColumn(Column<T, ?> column, String header) { 334 view.addColumn(column, header); 335 } 336 337 @Override 338 public final void insertColumn(int beforeIndex, Column<T, ?> col, String header) { 339 view.insertColumn(beforeIndex, col, header); 340 } 341 342 @Override 343 public final void removeColumn(int colIndex) { 344 view.removeColumn(colIndex); 345 } 346 347 @Override 348 public final void removeColumns() { 349 view.removeColumns(); 350 } 351 352 @Override 353 public final List<Column<T, ?>> getColumns() { 354 return view.getColumns(); 355 } 356 357 @Override 358 public final int getColumnOffset() { 359 return view.getColumnOffset(); 360 } 361 362 @Override 363 public final void sort(int columnIndex) { 364 view.sort(columnIndex); 365 } 366 367 @Override 368 public final void sort(int columnIndex, SortDir dir) { 369 view.sort(columnIndex, dir); 370 } 371 372 @Override 373 public final void sort(Column<T, ?> column) { 374 view.sort(column); 375 } 376 377 @Override 378 public final void sort(Column<T, ?> column, SortDir dir) { 379 view.sort(column, dir); 380 } 381 382 @Override 383 public final void setDataSource(DataSource<T> dataSource) { 384 view.setDataSource(dataSource); 385 } 386 387 @Override 388 public final DataSource<T> getDataSource() { 389 return view.getDataSource(); 390 } 391 392 @Override 393 public void loaded(int startIndex, List<T> data) { 394 view.loaded(startIndex, data); 395 } 396 397 @Override 398 public final void setRenderer(Renderer<T> renderer) { 399 view.setRenderer(renderer); 400 } 401 402 @Override 403 public final int getTotalRows() { 404 return view.getTotalRows(); 405 } 406 407 @Override 408 public final void setTotalRows(int totalRows) { 409 view.setTotalRows(totalRows); 410 } 411 412 @Override 413 public final int getRowHeight() { 414 return view.getRowHeight(); 415 } 416 417 @Override 418 public final void setRowHeight(int rowHeight) { 419 view.setRowHeight(rowHeight); 420 } 421 422 @Override 423 public final void updateRow(T model) { 424 view.updateRow(model); 425 } 426 427 @Override 428 public List<RowComponent<T>> getRows() { 429 return view.getRows(); 430 } 431 432 @Override 433 public final RowComponent<T> getRow(T model) { 434 return view.getRow(model); 435 } 436 437 @Override 438 public final RowComponent<T> getRow(int index) { 439 return view.getRow(index); 440 } 441 442 @Override 443 public final RowComponent<T> getRowByModel(T model) { 444 return view.getRowByModel(model); 445 } 446 447 @Override 448 public final void clearRows(boolean clearData) { 449 view.clearRows(clearData); 450 } 451 452 @Override 453 public final void setRowFactory(RowComponentFactory<T> rowFactory) { 454 view.setRowFactory(rowFactory); 455 } 456 457 @Override 458 public RowComponentFactory<T> getRowFactory() { 459 return view.getRowFactory(); 460 } 461 462 @Override 463 public final void setSelectionType(SelectionType selectionType) { 464 view.setSelectionType(selectionType); 465 } 466 467 @Override 468 public final SelectionType getSelectionType() { 469 return view.getSelectionType(); 470 } 471 472 @Override 473 public final void selectAllRows(boolean select) { 474 view.selectAllRows(select); 475 } 476 477 @Override 478 public final void selectAllRows(boolean select, boolean fireEvent) { 479 view.selectAllRows(select, fireEvent); 480 } 481 482 @Override 483 public final void selectRow(Element row, boolean fireEvent) { 484 view.selectRow(row, fireEvent); 485 } 486 487 @Override 488 public final void deselectRow(Element row, boolean fireEvent) { 489 view.deselectRow(row, fireEvent); 490 } 491 492 @Override 493 public final boolean hasDeselectedRows(boolean visibleOnly) { 494 return view.hasDeselectedRows(visibleOnly); 495 } 496 497 @Override 498 public final boolean hasSelectedRows(boolean visibleOnly) { 499 return view.hasSelectedRows(visibleOnly); 500 } 501 502 @Override 503 public final List<T> getSelectedRowModels(boolean visibleOnly) { 504 return view.getSelectedRowModels(visibleOnly); 505 } 506 507 @Override 508 public final boolean isUseStickyHeader() { 509 return view.isUseStickyHeader(); 510 } 511 512 @Override 513 public final void setUseStickyHeader(boolean stickyHeader) { 514 view.setUseStickyHeader(stickyHeader); 515 } 516 517 @Override 518 public final boolean isUseCategories() { 519 return view.isUseCategories(); 520 } 521 522 @Override 523 public final void setUseCategories(boolean useCategories) { 524 view.setUseCategories(useCategories); 525 } 526 527 @Override 528 public final boolean isUseLoadOverlay() { 529 return view.isUseLoadOverlay(); 530 } 531 532 @Override 533 public final void setUseLoadOverlay(boolean useLoadOverlay) { 534 view.setUseLoadOverlay(useLoadOverlay); 535 } 536 537 @Override 538 public final boolean isUseRowExpansion() { 539 return view.isUseRowExpansion(); 540 } 541 542 @Override 543 public final void setUseRowExpansion(boolean useRowExpansion) { 544 view.setUseRowExpansion(useRowExpansion); 545 } 546 547 @Override 548 public final int getLongPressDuration() { 549 return view.getLongPressDuration(); 550 } 551 552 @Override 553 public final void setLongPressDuration(int longPressDuration) { 554 view.setLongPressDuration(longPressDuration); 555 } 556 557 @Override 558 public final String getHeight() { 559 return view.getHeight(); 560 } 561 562 @Override 563 public final void setHeight(String height) { 564 view.setHeight(height); 565 } 566 567 @Override 568 public void onBrowserEvent(Event event) { 569 CellBasedWidgetImpl.get().onBrowserEvent(this, event); 570 571 // Ignore spurious events (such as onblur) while we refresh the table. 572 if (refreshing) { 573 return; 574 } 575 576 // Verify that the target is still a child of this widget. IE fires focus 577 // events even after the element has been removed from the DOM. 578 EventTarget eventTarget = event.getEventTarget(); 579 if (!Element.is(eventTarget)) { 580 return; 581 } 582 Element target = Element.as(eventTarget); 583 if (!getElement().isOrHasChild(Element.as(eventTarget))) { 584 return; 585 } 586 super.onBrowserEvent(event); 587 588 String eventType = event.getType(); 589 if (BrowserEvents.FOCUS.equals(eventType)) { 590 // Remember the focus state. 591 focused = true; 592 onFocus(); 593 } else if (BrowserEvents.BLUR.equals(eventType)) { 594 // Remember the blur state. 595 focused = false; 596 onBlur(); 597 } else if (BrowserEvents.KEYDOWN.equals(eventType)) { 598 // A key event indicates that we already have focus. 599 focused = true; 600 } else if (BrowserEvents.MOUSEDOWN.equals(eventType) 601 && CellBasedWidgetImpl.get().isFocusable(Element.as(target))) { 602 // If a natively focusable element was just clicked, then we must have 603 // focus. 604 focused = true; 605 } 606 } 607 608 protected void onFocus() { 609 // Do nothing by default 610 } 611 612 protected void onBlur() { 613 // Do nothing by default 614 } 615 616 /** 617 * Get the index of the row value from the associated {@link TableRowElement}. 618 * 619 * @param row the row element 620 * @return the row value index 621 */ 622 public final int getRowValueIndex(TableRowElement row) { 623 return row.getSectionRowIndex() + getView().getVisibleRange().getStart(); 624 } 625 626 /** 627 * Fire an event to the Cell within the specified {@link TableCellElement}. 628 */ 629 private <C> void fireEventToCell(Event event, String eventType, Element parentElem, 630 final T rowValue, Context context, HasCell<T, C> column) { 631 // Check if the cell consumes the event. 632 Cell<C> cell = column.getCell(); 633 if (!cellConsumesEventType(cell, eventType)) { 634 return; 635 } 636 637 C cellValue = column.getValue(rowValue); 638 boolean cellWasEditing = cell.isEditing(context, parentElem, cellValue); 639 if (column instanceof Column) { 640 /* 641 * If the HasCell is a Column, let it handle the event itself. This is 642 * here for legacy support. 643 */ 644 Column<T, C> col = (Column<T, C>) column; 645 col.onBrowserEvent(context, parentElem, rowValue, event); 646 } else { 647 // Create a FieldUpdater. 648 final FieldUpdater<T, C> fieldUpdater = column.getFieldUpdater(); 649 final int index = context.getIndex(); 650 ValueUpdater<C> valueUpdater = (fieldUpdater == null) ? null : (value) -> { 651 fieldUpdater.update(index, rowValue, value); 652 }; 653 654 // Fire the event to the cell. 655 cell.onBrowserEvent(context, parentElem, cellValue, event, valueUpdater); 656 } 657 658 // Reset focus if needed. 659 cellIsEditing = cell.isEditing(context, parentElem, cellValue); 660 if (cellWasEditing && !cellIsEditing) { 661 CellBasedWidgetImpl.get().resetFocus(() -> { 662 setFocus(true); 663 }); 664 } 665 } 666 667 /** 668 * Check if a cell consumes the specified event type. 669 * 670 * @param cell the cell 671 * @param eventType the event type to check 672 * @return true if consumed, false if not 673 */ 674 protected boolean cellConsumesEventType(Cell<?> cell, String eventType) { 675 Set<String> consumedEvents = cell.getConsumedEvents(); 676 return consumedEvents != null && consumedEvents.contains(eventType); 677 } 678 679 /** 680 * Get the tables scaffolding elements. 681 */ 682 @Override 683 public TableScaffolding getScaffolding() { 684 return scaffolding; 685 } 686 687 /** 688 * @deprecated use {@link #addSetupHandler(SetupHandler)} 689 */ 690 @Deprecated 691 public void setLoadedCallback(LoadedCallback callback) { 692 if(setupHandler != null) { 693 setupHandler.removeHandler(); 694 setupHandler = null; 695 } 696 setupHandler = addSetupHandler(event -> { 697 callback.onLoaded(); 698 }); 699 } 700 701 /** 702 * Event fired when the tables view calls {@link DataView#setup(TableScaffolding)}. 703 * @return Handler registration to remove the event handler. 704 */ 705 public HandlerRegistration addSetupHandler(SetupHandler handler) { 706 return addHandler(handler, SetupEvent.TYPE); 707 } 708 709 /** 710 * Event fired when the tables view calls {@link DataView#destroy()}. 711 * @return Handler registration to remove the event handler. 712 */ 713 public HandlerRegistration addDestroyHandler(DestroyHandler handler) { 714 return addHandler(handler, DestroyEvent.TYPE); 715 } 716 717 /** 718 * Event fired when the tables view calls {@link DataView#insertColumn(int, Column, String)}. 719 * @return Handler registration to remove the event handler. 720 */ 721 public HandlerRegistration addInsertColumnHandler(InsertColumnHandler<T> handler) { 722 return addHandler(handler, InsertColumnEvent.TYPE); 723 } 724 725 /** 726 * Event fired when the tables view calls {@link DataView#removeColumn(int)}. 727 * @return Handler registration to remove the event handler. 728 */ 729 public HandlerRegistration addRemoveColumnHandler(RemoveColumnHandler handler) { 730 return addHandler(handler, RemoveColumnEvent.TYPE); 731 } 732 733 public boolean isDestroyOnUnload() { 734 return destroyOnUnload; 735 } 736 737 public void setDestroyOnUnload(boolean destroyOnUnload) { 738 this.destroyOnUnload = destroyOnUnload; 739 } 740 741 // Event Handlers 742 743 @Override 744 public HandlerRegistration registerHandler(HandlerRegistration registration) { 745 return handlerRegistry.registerHandler(registration); 746 } 747 748 @Override 749 public void clearHandlers() { 750 handlerRegistry.clearHandlers(); 751 } 752 753 @Override 754 public HandlerRegistration addSelectAllHandler(SelectAllHandler<T> handler) { 755 return addHandler(handler, SelectAllEvent.TYPE); 756 } 757 758 @Override 759 public HandlerRegistration addRowSelectHandler(RowSelectHandler<T> handler) { 760 return addHandler(handler, RowSelectEvent.TYPE); 761 } 762 763 @Override 764 public HandlerRegistration addRowExpandingHandler(RowExpandingHandler<T> handler) { 765 return addHandler(handler, RowExpandingEvent.TYPE); 766 } 767 768 @Override 769 public HandlerRegistration addRowExpandedHandler(RowExpandedHandler<T> handler) { 770 return addHandler(handler, RowExpandedEvent.TYPE); 771 } 772 773 @Override 774 public HandlerRegistration addRowCollapseHandler(RowCollapsingHandler<T> handler) { 775 return addHandler(handler, RowCollapsingEvent.TYPE); 776 } 777 778 @Override 779 public HandlerRegistration addRowCollapsedHandler(RowCollapsedHandler<T> handler) { 780 return addHandler(handler, RowCollapsedEvent.TYPE); 781 } 782 783 @Override 784 public HandlerRegistration addRowContextMenuHandler(RowContextMenuHandler<T> handler) { 785 return addHandler(handler, RowContextMenuEvent.TYPE); 786 } 787 788 @Override 789 public HandlerRegistration addRowDoubleClickHandler(RowDoubleClickHandler<T> handler) { 790 return addHandler(handler, RowDoubleClickEvent.TYPE); 791 } 792 793 @Override 794 public HandlerRegistration addRowLongPressHandler(RowLongPressHandler<T> handler) { 795 return addHandler(handler, RowLongPressEvent.TYPE); 796 } 797 798 @Override 799 public HandlerRegistration addRowShortPressHandler(RowShortPressHandler<T> handler) { 800 return addHandler(handler, RowShortPressEvent.TYPE); 801 } 802 803 @Override 804 public HandlerRegistration addColumnSortHandler(ColumnSortHandler<T> handler) { 805 return addHandler(handler, ColumnSortEvent.TYPE); 806 } 807 808 @Override 809 public HandlerRegistration addCategoryOpenedHandler(CategoryOpenedHandler handler) { 810 return addHandler(handler, CategoryOpenedEvent.TYPE); 811 } 812 813 @Override 814 public HandlerRegistration addCategoryClosedHandler(CategoryClosedHandler handler) { 815 return addHandler(handler, CategoryClosedEvent.TYPE); 816 } 817 818 @Override 819 public HandlerRegistration addComponentsRenderedHandler(ComponentsRenderedHandler handler) { 820 return addHandler(handler, ComponentsRenderedEvent.TYPE); 821 } 822 823 @Override 824 public HandlerRegistration addRenderedHandler(RenderedHandler handler) { 825 return addHandler(handler, RenderedEvent.TYPE); 826 } 827}