private void handleRowClick(MouseDownEvent event, TableRowElement row) {
    int modifiers = KeyboardShortcut.getModifierValue(event.getNativeEvent());
    modifiers &= ~KeyboardShortcut.ALT; // ALT has no effect

    if (!allowMultiSelect_) modifiers = KeyboardShortcut.NONE;

    // We'll treat Ctrl and Meta as equivalent--and normalize to Ctrl.
    if (KeyboardShortcut.META == (modifiers & KeyboardShortcut.META))
      modifiers |= KeyboardShortcut.CTRL;
    modifiers &= ~KeyboardShortcut.META;

    if (modifiers == KeyboardShortcut.NONE) {
      // Select only the target row
      clearSelection();
      setSelected(row, true);
    } else if (modifiers == KeyboardShortcut.CTRL) {
      // Toggle the target row
      setSelected(row, !isSelected(row));
    } else {
      // SHIFT or CTRL+SHIFT

      int target = row.getRowIndex();
      Integer min = null;
      Integer max = null;
      for (TableRowElement selectedRow : selectedRows_) {
        if (min == null) min = selectedRow.getRowIndex();
        max = selectedRow.getRowIndex();
      }

      int offset; // selection offset
      int length; // selection length

      if (min == null) {
        // Nothing is selected
        offset = target;
        length = 1;
      } else if (target < min) {
        // Select target..max
        offset = target;
        length = max - target + 1;
      } else if (target > max) {
        offset = min;
        length = target - min + 1;
      } else {
        // target is in between min and max
        if (modifiers == (KeyboardShortcut.CTRL | KeyboardShortcut.SHIFT)) {
          offset = min;
          length = target - min + 1;
        } else {
          offset = target;
          length = 1;
        }
      }

      clearSelection();
      if (length > 0) {
        setSelectedPhysical(offset, length, true);
      }
    }
  }
  public ArrayList<Integer> getSelectedRowIndexes() {
    sortSelectedRows();

    ArrayList<Integer> results = new ArrayList<Integer>();
    for (TableRowElement row : selectedRows_)
      results.add(codec_.physicalOffsetToLogicalOffset(table_, row.getRowIndex()));
    return results;
  }
  private int removeTopRows(TableSectionElement tbody, int rowCount) {
    while (rowCount > 0 && tbody.getRows().getLength() >= 0) {
      TableRowElement topRow = tbody.getRows().getItem(0);
      if (codec_.isValueRow(topRow)) rowCount--;
      selectedRows_.remove(topRow);
      topRow.removeFromParent();
    }

    if (tbody.getRows().getLength() > 0) codec_.onRowsChanged(tbody);
    else tbody.removeFromParent();

    return rowCount;
  }
  public void setSelected(TableRowElement row, boolean selected) {
    try {
      if (row.getParentElement().getParentElement() != table_) return;
    } catch (NullPointerException npe) {
      return;
    }

    boolean isCurrentlySelected = isSelected(row);
    if (isCurrentlySelected == selected) return;

    if (selected && !codec_.isValueRow(row)) return;

    setStyleName(row, selectedClassName_, selected);
    if (selected) selectedRows_.add(row);
    else selectedRows_.remove(row);

    if (selected && !allowMultiSelect_) {
      Scheduler.get()
          .scheduleDeferred(
              new ScheduledCommand() {
                public void execute() {
                  fireEvent(new SelectionChangedEvent());
                }
              });
    }
  }
  public Rectangle getSelectionRect() {
    if (selectedRows_.size() == 0) return null;

    sortSelectedRows();

    TableRowElement first = selectedRows_.get(0);
    TableRowElement last = selectedRows_.get(selectedRows_.size() - 1);
    int top = first.getOffsetTop();
    int bottom = last.getOffsetTop() + last.getOffsetHeight();
    int left = first.getOffsetLeft();
    int width = first.getOffsetWidth();
    return new Rectangle(left, top, width, bottom - top);
  }
 private boolean isSelected(TableRowElement tr) {
   return tr.getClassName().contains(selectedClassName_);
 }