Coverage Report - org.kuali.student.common.ui.client.widgets.table.scroll.Table
 
Classes in this File Line Coverage Branch Coverage Complexity
Table
0%
0/212
0%
0/104
2.488
Table$1
0%
0/9
0%
0/6
2.488
Table$2
0%
0/9
0%
0/6
2.488
Table$3
0%
0/11
0%
0/8
2.488
Table$4
0%
0/3
N/A
2.488
Table$5
0%
0/3
N/A
2.488
Table$6
0%
0/3
N/A
2.488
Table$7
0%
0/3
N/A
2.488
Table$8
0%
0/3
N/A
2.488
Table$FocusType
0%
0/2
N/A
2.488
Table$SelectionStyle
N/A
N/A
2.488
Table$TableUiBinder
N/A
N/A
2.488
 
 1  
 package org.kuali.student.common.ui.client.widgets.table.scroll;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.List;
 5  
 
 6  
 import org.kuali.student.common.ui.client.util.BrowserUtils;
 7  
 import org.kuali.student.common.ui.client.util.DebugIdUtils;
 8  
 import org.kuali.student.common.ui.client.widgets.list.HasSelectionChangeHandlers;
 9  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
 10  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
 11  
 import org.kuali.student.common.ui.client.widgets.notification.LoadingDiv;
 12  
 
 13  
 import com.google.gwt.core.client.GWT;
 14  
 import com.google.gwt.event.dom.client.ChangeEvent;
 15  
 import com.google.gwt.event.dom.client.ChangeHandler;
 16  
 import com.google.gwt.event.dom.client.ClickEvent;
 17  
 import com.google.gwt.event.dom.client.ClickHandler;
 18  
 import com.google.gwt.event.dom.client.HasChangeHandlers;
 19  
 import com.google.gwt.event.dom.client.HasClickHandlers;
 20  
 import com.google.gwt.event.dom.client.KeyCodes;
 21  
 import com.google.gwt.event.dom.client.KeyDownEvent;
 22  
 import com.google.gwt.event.dom.client.KeyDownHandler;
 23  
 import com.google.gwt.event.dom.client.ScrollEvent;
 24  
 import com.google.gwt.event.dom.client.ScrollHandler;
 25  
 import com.google.gwt.event.shared.HandlerRegistration;
 26  
 import com.google.gwt.resources.client.CssResource;
 27  
 import com.google.gwt.uibinder.client.UiBinder;
 28  
 import com.google.gwt.uibinder.client.UiField;
 29  
 import com.google.gwt.uibinder.client.UiHandler;
 30  
 import com.google.gwt.user.client.Element;
 31  
 import com.google.gwt.user.client.ui.CheckBox;
 32  
 import com.google.gwt.user.client.ui.Composite;
 33  
 import com.google.gwt.user.client.ui.FlexTable;
 34  
 import com.google.gwt.user.client.ui.FocusPanel;
 35  
 import com.google.gwt.user.client.ui.HTMLPanel;
 36  
 import com.google.gwt.user.client.ui.Label;
 37  
 import com.google.gwt.user.client.ui.ScrollPanel;
 38  
 import com.google.gwt.user.client.ui.Widget;
 39  
 import com.google.gwt.user.client.ui.HTMLTable.Cell;
 40  
 import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
 41  
 
 42  
 /**
 43  
  * A table with UiBinder.
 44  
  */
 45  0
 public class Table extends Composite implements HasRetrieveAdditionalDataHandlers, HasSelectionChangeHandlers {
 46  
 
 47  0
     private int headerSelectedCellIndex = -1;
 48  
 
 49  0
     private FocusType focusType = FocusType.NONE;
 50  
 
 51  0
     private static TableUiBinder uiBinder = GWT.create(TableUiBinder.class);
 52  0
     private final List<RetrieveAdditionalDataHandler> retrieveDataHandlers = new ArrayList<RetrieveAdditionalDataHandler>();
 53  
 
 54  
     interface TableUiBinder extends UiBinder<Widget, Table> {}
 55  
 
 56  
     interface SelectionStyle extends CssResource {
 57  
         String selectedRow();
 58  
 
 59  
         String columnAscending();
 60  
 
 61  
         String columnDescending();
 62  
 
 63  
         String selectedHeaderCell();
 64  
     }
 65  
 
 66  0
     private static enum FocusType {
 67  0
         HEADER, BODY, NONE
 68  
     }
 69  
 
 70  
     @UiField
 71  
     FlexTable header;
 72  
     @UiField
 73  
     MouseHoverFlexTable table;
 74  
     @UiField
 75  
     SelectionStyle selectionStyle;
 76  
     @UiField
 77  
     ScrollPanel scrollPanel;
 78  
     @UiField
 79  
     FocusPanel focusPanel;
 80  
     @UiField
 81  
     FocusPanel headerFocusPanel;
 82  
     @UiField
 83  
     HTMLPanel panel;
 84  
 
 85  
     private TableModel tableModel;
 86  0
     private final LoadingDiv loading = new LoadingDiv();
 87  
 
 88  0
     public Table() {
 89  0
         initWidget(uiBinder.createAndBindUi(this));
 90  
 
 91  0
         scrollPanel.addScrollHandler(new ScrollHandler() {
 92  
             @Override
 93  
             public void onScroll(ScrollEvent event) {
 94  0
                 int position = scrollPanel.getScrollPosition();
 95  
                 // see 6th comment in KSLAB-1790; possibly not created yet?
 96  0
                 if (null != scrollPanel.getWidget()) {
 97  0
                     int size = scrollPanel.getWidget().getOffsetHeight();
 98  0
                     int diff = size - scrollPanel.getOffsetHeight();
 99  0
                     if (position == diff) {
 100  0
                         for (int i = 0; i < retrieveDataHandlers.size(); i++) {
 101  0
                             retrieveDataHandlers.get(i).onAdditionalDataRequest();
 102  
                         }
 103  
                     }
 104  
                 }
 105  0
             }
 106  
         });
 107  0
         addHandlers();
 108  0
     }
 109  
 
 110  
     public void removeAllRows() {
 111  0
         table.removeAllRows();
 112  0
     }
 113  
 
 114  
     public void removeContent() {
 115  0
         getScrollPanel().clear();
 116  0
     }
 117  
 
 118  
     public void addContent() {
 119  0
         getScrollPanel().setWidget(getContent());
 120  0
     }
 121  
 
 122  
     private void addHandlers() {
 123  0
         focusPanel.addKeyDownHandler(new KeyDownHandler() {
 124  
 
 125  
             @Override
 126  
             public void onKeyDown(KeyDownEvent event) {
 127  0
                 int code = event.getNativeKeyCode();
 128  0
                 if (code == KeyCodes.KEY_DOWN) {
 129  0
                     processKeyUpAndDownEvent(TablePredicateFactory.DOWN_RIGHT_PREDICATE);
 130  0
                 } else if (code == KeyCodes.KEY_UP) {
 131  0
                     processKeyUpAndDownEvent(TablePredicateFactory.UP_LEFT_PREDICATE);
 132  0
                 } else if (code == ' ') {
 133  0
                     processSpaceClick();
 134  
                 }
 135  0
             }
 136  
         });
 137  0
         headerFocusPanel.addKeyDownHandler(new KeyDownHandler() {
 138  
             @Override
 139  
             public void onKeyDown(KeyDownEvent event) {
 140  0
                 int code = event.getNativeKeyCode();
 141  0
                 if (code == KeyCodes.KEY_RIGHT) {
 142  0
                     processKeyLeftRight(TablePredicateFactory.DOWN_RIGHT_PREDICATE);
 143  0
                 } else if (code == KeyCodes.KEY_LEFT) {
 144  0
                     processKeyLeftRight(TablePredicateFactory.UP_LEFT_PREDICATE);
 145  0
                 } else if (code == KeyCodes.KEY_DOWN) {
 146  0
                     processKeyDownOnHeader();
 147  0
                 } else if (code == ' ') {
 148  0
                     onTableHeaderClicked(headerSelectedCellIndex, true);
 149  
                 }
 150  0
             }
 151  
         });
 152  0
     }
 153  
 
 154  
     private void processKeyDownOnHeader() {
 155  0
         changeFocus(FocusType.BODY);
 156  0
         Row currentRow = tableModel.getRow(0);
 157  0
         tableModel.setCurrentIndex(0);
 158  0
         currentRow.setHighlighted(true);
 159  0
         updateTableSelection();
 160  0
         removeHeaderSelection();
 161  0
     }
 162  
 
 163  
     private void removeHeaderSelection() {
 164  0
         if (headerSelectedCellIndex >= 0) {
 165  0
             header.getCellFormatter().removeStyleName(0, headerSelectedCellIndex, selectionStyle.selectedHeaderCell());
 166  0
             headerSelectedCellIndex = -1;
 167  
         }
 168  0
     }
 169  
 
 170  
     private void processKeyLeftRight(TablePredicateFactory.Predicate tablePredicate) {
 171  0
         if (tablePredicate.indexCondition(headerSelectedCellIndex, tableModel.getColumnCount())) {
 172  0
             header.getCellFormatter().removeStyleName(0, headerSelectedCellIndex, selectionStyle.selectedHeaderCell());
 173  0
             headerSelectedCellIndex = tablePredicate.nextIndex(headerSelectedCellIndex);
 174  0
             header.getCellFormatter().addStyleName(0, headerSelectedCellIndex, selectionStyle.selectedHeaderCell());
 175  
 
 176  
         }
 177  0
     }
 178  
 
 179  
     private void processSpaceClick() {
 180  0
         int index = tableModel.getCurrentIndex();
 181  0
         if (index >= 0) {
 182  0
             Row currentRow = tableModel.getRow(index);
 183  0
             boolean selected = currentRow.isSelected();
 184  0
             if (selected) {
 185  0
                 currentRow.setSelected(false);
 186  
             } else {
 187  0
                 tableModel.setSelectedRow(index);
 188  
             }
 189  0
             updateTableSelection();
 190  
         }
 191  0
     }
 192  
 
 193  
     private void processKeyUpAndDownEvent(TablePredicateFactory.Predicate tablePredicate) {
 194  0
         int currentIndex = tableModel.getCurrentIndex();
 195  0
         Row currentRow = tableModel.getRow(currentIndex);
 196  0
         if (currentIndex == 0 && tablePredicate.moveType() == TablePredicateFactory.MoveType.UP_LEFT) {
 197  0
             tableModel.getRow(currentIndex).setHighlighted(false);
 198  0
             tableModel.setCurrentIndex(-1);
 199  0
             headerSelectedCellIndex = 0;
 200  0
             changeFocus(FocusType.HEADER);
 201  0
             header.getCellFormatter().addStyleName(0, 0, selectionStyle.selectedHeaderCell());
 202  
         } else {
 203  0
             if (currentRow.isHighlighted() && tablePredicate.indexCondition(currentIndex, tableModel.getRowCount())) {
 204  0
                 currentRow.setHighlighted(false);
 205  0
                 currentIndex = tablePredicate.nextIndex(currentIndex);
 206  0
                 tableModel.getRow(currentIndex).setHighlighted(true);
 207  0
                 tableModel.setCurrentIndex(currentIndex);
 208  0
                 scrollPanel.ensureVisible(table.getWidget(currentIndex, 0));
 209  
             }
 210  
         }
 211  0
         updateTableSelection();
 212  0
     }
 213  
 
 214  
     public FlexTable getHeader() {
 215  0
         return header;
 216  
     }
 217  
 
 218  
     public FlexTable getContent() {
 219  0
         return table;
 220  
     }
 221  
 
 222  
     public ScrollPanel getScrollPanel() {
 223  0
         return scrollPanel;
 224  
     }
 225  
 
 226  
     public void setTableModel(TableModel m) {
 227  0
         tableModel = m;
 228  0
         table.setModel(tableModel);
 229  0
         if (m instanceof AbstractTableModel) {
 230  0
             ((AbstractTableModel) tableModel).addTableModelListener(new TableModelListener() {
 231  
                 @Override
 232  
                 public void tableChanged(TableModelEvent e) {
 233  0
                     updateTable(e);
 234  0
                 }
 235  
             });
 236  0
             ((AbstractTableModel) tableModel).fireTableStructureChanged();
 237  
         }
 238  0
     }
 239  
 
 240  
     public TableModel getTableModel() {
 241  0
         return tableModel;
 242  
     }
 243  
 
 244  
     @UiHandler("table")
 245  
     void onTableClicked(ClickEvent event) {
 246  0
         removeHeaderSelection();
 247  
         // changeFocus(FocusType.BODY);
 248  0
         Cell cell = table.getCellForEvent(event);
 249  
 
 250  0
         if (cell == null) {
 251  0
             return;
 252  
         }
 253  0
         int cellIndex = cell.getCellIndex();
 254  0
         int rowIndex = cell.getRowIndex();
 255  0
         tableModel.setCurrentIndex(rowIndex);
 256  0
         Row row = tableModel.getRow(rowIndex);
 257  
 
 258  0
         if (tableModel.isMultipleSelectable() == false) {
 259  0
             for (int r = 0; r < tableModel.getRowCount(); r++) {
 260  0
                 if (r != rowIndex) {
 261  0
                     tableModel.getRow(r).setSelected(false);
 262  
                 }
 263  
             }
 264  0
             row.setSelected(!row.isSelected());
 265  0
             updateTableSelection();
 266  0
             for (int r = 0; r < tableModel.getRowCount(); r++) {
 267  0
                 updateTableCell(r, 0);
 268  
             }
 269  
         } else {
 270  0
             if (cellIndex == 0) {
 271  0
                 return;
 272  
             }
 273  0
             row.setSelected(!row.isSelected());
 274  0
             updateTableSelection();
 275  0
             updateTableCell(rowIndex, 0);
 276  
         }
 277  0
     }
 278  
 
 279  
     @UiHandler("header")
 280  
     void onTableHeaderClicked(ClickEvent event) {
 281  0
         Cell cell = header.getCellForEvent(event);
 282  0
         if (cell != null) {
 283  0
             onTableHeaderClicked(cell.getCellIndex(), false);
 284  
         }
 285  0
     }
 286  
 
 287  
     private void onTableHeaderClicked(int cellIndex, boolean propagateEventIfNotSortingColumn) {
 288  0
         if (cellIndex == 0 && tableModel.isMultipleSelectable() && propagateEventIfNotSortingColumn) {
 289  0
             Widget widget = header.getWidget(0, 0);
 290  0
             if (widget instanceof CheckBox) {
 291  0
                 CheckBox checkBox = (CheckBox) widget;
 292  0
                 boolean correctValue = !checkBox.getValue();
 293  0
                 checkBox.setValue(correctValue);
 294  0
                 for (int row = 0; row < tableModel.getRowCount(); row++) {
 295  0
                     tableModel.getRow(row).setSelected(correctValue);
 296  0
                     updateTableSelection();
 297  
                 }
 298  
             }
 299  0
         } else {
 300  0
             removeHeaderSelection();
 301  
         }
 302  0
         headerSelectedCellIndex = cellIndex;
 303  0
         Column col = tableModel.getColumn(cellIndex);
 304  0
         tableModel.sort(col);
 305  0
     }
 306  
 
 307  
     private void onTableClicked(int row, String columnId, TableCellWidget cellWidget) {
 308  0
         onTableCellChanged(row, columnId, cellWidget);
 309  0
     }
 310  
 
 311  
     private void onTableCellChanged(int rowIndex, String columnId, TableCellWidget cellWidget) {
 312  0
         Row row = tableModel.getRow(rowIndex);
 313  0
         if ("RowHeader".equals(columnId)) {
 314  0
             row.setSelected(!row.isSelected());
 315  0
             updateTableSelection();
 316  
         }
 317  0
         row.setCellData(columnId, cellWidget.getCellEditorValue());
 318  0
     }
 319  
 
 320  
     private void updateTableSelection() {
 321  0
         int count = tableModel.getRowCount();
 322  0
         String attrName = BrowserUtils.getClassAttr();
 323  0
         for (int i = 0; i < count; i++) {
 324  0
             Element tr = table.getRowFormatter().getElement(i);
 325  0
             if (tableModel.getRow(i).isSelected()) {
 326  0
                 tr.setAttribute(attrName, "table-row-selected");
 327  
             } else {
 328  0
                 tr.setAttribute(attrName, "table-row");
 329  
             }
 330  0
             if (tableModel.getRow(i).isHighlighted()) {
 331  0
                 tr.setAttribute(attrName, "table-row-hover");
 332  
             }
 333  0
             if (tableModel.isMultipleSelectable()) {
 334  0
                 updateTableCell(i, 0);
 335  
             }
 336  
         }
 337  0
         SelectionChangeEvent.fire(this);
 338  0
     }
 339  
 
 340  
     private void changeFocus(FocusType focusType) {
 341  0
         this.focusType = focusType;
 342  0
         if (focusType == FocusType.HEADER) {
 343  0
             headerFocusPanel.setFocus(true);
 344  0
         } else if (focusType == FocusType.BODY) {
 345  0
             focusPanel.setFocus(true);
 346  
         }
 347  0
     }
 348  
 
 349  
     public void updateTable(TableModelEvent event) {
 350  0
         if (event.getType() == TableModelEvent.TableStructure) {
 351  0
             updateTableStructure();
 352  0
             updateTableData();
 353  0
         } else if (event.getType() == TableModelEvent.TableData) {
 354  0
             updateTableData();
 355  0
         } else if (event.getType() == TableModelEvent.CellUpdate) {
 356  0
             updateTableCell(event.getFirstRow(), event.getColumn());
 357  
         }
 358  0
     }
 359  
 
 360  
     private void updateTableData() {
 361  0
         for (int r = 0; r < tableModel.getRowCount(); r++) {
 362  0
             int columnCount = tableModel.getColumnCount();
 363  0
             for (int c = 0; c < columnCount; c++) {
 364  0
                 updateTableCell(r, c);
 365  
             }
 366  
         }
 367  0
         updateTableSelection();
 368  0
     }
 369  
 
 370  
     private void updateTableCell(final int r, final int c) {
 371  0
         int columnCount = tableModel.getColumnCount();
 372  0
         for (int i = 0; i < columnCount - 1; i++) {
 373  0
             Column col = tableModel.getColumn(i);
 374  0
             table.getColumnFormatter().setWidth(i, col.getWidth());
 375  
         }
 376  0
         final String columnId = tableModel.getColumn(c).getId();
 377  0
         Row row = tableModel.getRow(r);
 378  0
         Object v = null;
 379  0
         if ("RowHeader".equals(columnId)) {
 380  0
             v = row.isSelected();
 381  
         } else {
 382  0
             v = row.getCellData(columnId);
 383  
         }
 384  0
         if ("RowHeader".equals(columnId) == false) {
 385  0
             if (v != null) {
 386  0
                 table.setWidget(r, c, new Label(v.toString()));
 387  
             } else {
 388  0
                 table.setHTML(r, c, "&nbsp;");
 389  
             }
 390  0
             return;
 391  
         }
 392  0
         final TableCellWidget widget = new TableCellWidget(v);
 393  0
         final StringBuilder debugId = new StringBuilder();
 394  0
         if ("RowHeader".equals(columnId)) {
 395  
             //Setup debug id
 396  
             //Skip the first 'row selection' column
 397  0
             for (int i = 1; i < columnCount; i++) {
 398  0
                 Column column = tableModel.getColumn(i);
 399  0
                 Object value = row.getCellData(column.getId());
 400  0
                 debugId.append(value);
 401  0
                 if (i != columnCount - 1) {
 402  0
                     debugId.append("-");
 403  
                 }
 404  
             }
 405  0
             widget.getDefaultTableEditor().ensureDebugId(DebugIdUtils.createWebDriverSafeDebugId(debugId.toString()));
 406  
         }
 407  0
         widget.setCellEditorValue(v);
 408  0
         if (widget instanceof HasClickHandlers) {
 409  0
             ((HasClickHandlers) widget).addClickHandler(new ClickHandler() {
 410  
                 @Override
 411  
                 public void onClick(ClickEvent event) {
 412  0
                     onTableClicked(r, columnId, widget);
 413  0
                 }
 414  
             });
 415  
         }
 416  0
         if (widget instanceof HasChangeHandlers) {
 417  0
             ((HasChangeHandlers) widget).addChangeHandler(new ChangeHandler() {
 418  
                 @Override
 419  
                 public void onChange(ChangeEvent event) {
 420  0
                     onTableCellChanged(r, columnId, widget);
 421  
 
 422  0
                 }
 423  
             });
 424  
         }
 425  0
         table.setWidget(r, c, widget);
 426  0
     }
 427  
 
 428  
     private void updateTableStructure() {
 429  0
         int columnCount = tableModel.getColumnCount();
 430  0
         for (int i = 0; i < columnCount; i++) {
 431  0
             Column col = tableModel.getColumn(i);
 432  0
             header.setWidget(0, i, col.getColumnTitleWidget());
 433  
         }
 434  0
         for (int i = 0; i < columnCount - 1; i++) {
 435  0
             Column col = tableModel.getColumn(i);
 436  0
             header.getColumnFormatter().setWidth(i, col.getWidth());
 437  
         }
 438  0
         for (int i = 0; i < columnCount; i++) {
 439  0
             Column col = tableModel.getColumn(i);
 440  
 
 441  0
             header.getCellFormatter().removeStyleName(0, i, selectionStyle.columnAscending());
 442  0
             header.getCellFormatter().removeStyleName(0, i, selectionStyle.columnDescending());
 443  
 
 444  0
             if (col.getSortDirection() == Column.Ascending) {
 445  0
                 header.getCellFormatter().addStyleName(0, i, selectionStyle.columnAscending());
 446  0
             } else if (col.getSortDirection() == Column.Descending) {
 447  0
                 header.getCellFormatter().addStyleName(0, i, selectionStyle.columnDescending());
 448  
             }
 449  
         }
 450  0
     }
 451  
 
 452  
     @Override
 453  
     public HandlerRegistration addRetrieveAdditionalDataHandler(final RetrieveAdditionalDataHandler handler) {
 454  0
         retrieveDataHandlers.add(handler);
 455  0
         HandlerRegistration result = new HandlerRegistration() {
 456  
             @Override
 457  
             public void removeHandler() {
 458  0
                 retrieveDataHandlers.remove(handler);
 459  0
             }
 460  
         };
 461  0
         return result;
 462  
     }
 463  
 
 464  
     public void displayLoading(boolean isLoading) {
 465  0
         changeFocus(FocusType.BODY);
 466  0
         final int x = scrollPanel.getAbsoluteLeft() + scrollPanel.getOffsetWidth();
 467  0
         final int y = scrollPanel.getAbsoluteTop() + scrollPanel.getOffsetHeight();
 468  0
         if (isLoading) {
 469  0
             loading.setPopupPositionAndShow(new PositionCallback() {
 470  
 
 471  
                 @Override
 472  
                 public void setPosition(int offsetWidth, int offsetHeight) {
 473  0
                     loading.setPopupPosition(x - offsetWidth, y + 1);
 474  0
                 }
 475  
             });
 476  
         } else {
 477  0
             loading.hide();
 478  
         }
 479  0
     }
 480  
 
 481  
     /**
 482  
      * @see org.kuali.student.common.ui.client.widgets.list.HasSelectionChangeHandlers#addSelectionChangeHandler(org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler)
 483  
      */
 484  
     @Override
 485  
     public HandlerRegistration addSelectionChangeHandler(SelectionChangeHandler handler) {
 486  0
         return addHandler(handler, SelectionChangeEvent.getType());
 487  
     }
 488  
 }