private void appendRow(Row row) {
   if (row.object == null) {
     Widget groupWidget;
     try {
       groupWidget = createGroupWidget(row.group);
     } catch (Exception ex) {
       throw new RuntimeException(Str.getSimpleName(getClass()) + "getGroupWidget() failed");
     }
     table.setWidget(row.tableRowIndex, 0, groupWidget);
     table.getFlexCellFormatter().setColSpan(row.tableRowIndex, 0, columns.size());
   } else {
     for (AColumn column : columns) {
       table.setWidget(row.tableRowIndex, column.index, column.getCellWidget(row.object));
       column.formatCell(row.tableRowIndex, row.object, table.getCellFormatter());
     }
     if (isClickable()) {
       switch (getMouseover()) {
         case ROW:
           table.getRowFormatter().setStyleName(row.tableRowIndex, "clickable");
           break;
         case CELL:
           for (int col = 0; col < columns.size(); col++) {
             if (isColumnClickable(col)) {
               table.getCellFormatter().setStyleName(row.tableRowIndex, col, "clickable");
             }
           }
           break;
         case NONE:
           break;
       }
     }
   }
 }
 public boolean matchesColumnFilters() {
   if (group != null) return true;
   if (object == null) return false;
   for (AColumn column : columns) {
     if (!column.matchesFilter(object)) return false;
   }
   return true;
 }
 public void updateFootCells() {
   int rowIndex = -1;
   if (isColumnTitlesEnabled()) rowIndex++;
   if (isColumnFilteringEnabled()) rowIndex++;
   rowIndex += rows.size();
   for (int i = 0; i < getFootRowCount(); i++) {
     rowIndex++;
     for (AColumn column : columns) {
       table.setWidget(rowIndex, column.index, column.getFootCellWidget(i));
     }
   }
 }
  @Override
  public final Updatable update() {
    log.debug("update()");

    table = null;
    wrapper = null;
    rows = null;
    columns = new ArrayList<AColumn>();

    table = new FlexTable();
    table.getElement().setId(getId() + "_table");
    table.setStyleName("goon-ObjectTable");

    wrapper = new BuilderPanel();
    if (isCardStyle()) wrapper.setStyleCard();
    wrapper.setId(getId());
    // wrapper.setSpacing(0);
    if (getColorForMarker() != null) wrapper.addColorMarker(getColorForMarker());
    init(wrapper);
    wrapper.add(table);
    initWrapperAfterTable(wrapper);

    for (AColumn column : columns) {
      column.formatColumn(table.getColumnFormatter());
    }

    onTableAdded(wrapper, table);

    reverseSort = isReverseSort();
    try {
      onUpdate();
    } catch (Exception ex) {
      throw new RuntimeException(Str.getSimpleName(getClass()) + ".onUpdate() failed", ex);
    }

    asWidgetWrapper.clear();
    asWidgetWrapper.add(wrapper);

    return this;
  }
  protected void onUpdate() {
    if (sortColumnIndex == -1) {
      sortColumnIndex = getInitialSortColumnIndex();
      reverseSort = isInitialSortReverse();
    }

    Collection<O> objects;
    try {
      objects = getObjects();
    } catch (Exception ex) {
      throw new RuntimeException(Str.getSimpleName(getClass()) + ".getObjects() failed.", ex);
    }

    log.info("Objects loaded:", objects.size());

    int rowIndex = -1;

    if (isColumnTitlesEnabled()) {
      rowIndex++;
      for (AColumn column : columns) {
        String columnTitle;
        try {
          columnTitle = column.getTitle();
        } catch (Exception ex) {
          log.error(ex);
          columnTitle = "ERROR: " + Str.formatException(ex);
        }

        boolean customSortingEnabled = isCustomSortingEnabled();

        Widget titleWidget = Widgets.textFieldlabel(columnTitle, false);
        if (titleWidget != null && customSortingEnabled && isShowColumnSortingToggleIcon())
          titleWidget.addStyleName("columnTitleWithSortToggle");

        if (titleWidget != null && (sortColumnIndex == column.index)) {
          // Sortierte Spalte hervorheben
          Style style = titleWidget.getElement().getStyle();
          style.setColor("#444");
          style.setFontWeight(FontWeight.BOLD);
          if (reverseSort) style.setFontStyle(FontStyle.ITALIC);
        }

        table.setWidget(
            rowIndex,
            column.index,
            Widgets.frame(
                titleWidget,
                Widgets.defaultSpacing,
                0,
                Widgets.defaultSpacing,
                Widgets.defaultSpacing / 2));

        if (customSortingEnabled) {
          for (int col = 0; col < columns.size(); col++) {
            table.getCellFormatter().setStyleName(rowIndex, col, "clickable");
          }
        }
      }
    }

    if (isColumnFilteringEnabled()) {
      rowIndex++;
      for (AColumn column : columns) {
        TextBox filterTextbox = column.getFilterWidget();
        SimplePanel frame = Widgets.frame(filterTextbox, Widgets.defaultSpacing);
        table.setWidget(rowIndex, column.index, frame);
      }
    }

    try {
      rows = createRows(objects, rowIndex);
    } catch (Exception ex) {
      throw new RuntimeException(Str.getSimpleName(getClass()) + ".createRows() failed.", ex);
    }
    table.setVisible(!rows.isEmpty());

    for (Row row : rows) {
      appendRow(row);
      rowIndex++;
    }

    for (int i = 0; i < getFootRowCount(); i++) {
      rowIndex++;
      for (AColumn column : columns) {
        table.setWidget(rowIndex, column.index, column.getFootCellWidget(i));
      }
    }
  }
 public final void add(AColumn column) {
   column.index = columns.size();
   columns.add(column);
 }