GWT Celltable-Sorting on Multiple Column

时间:2015-07-29 04:53:52

标签: gwt gwt-celltable

如何使用GWT Celltable在多列上执行排序。我没有找到任何示例代码?见下图

enter image description here

我需要在多个列上执行服务器端排序。如何使用GWT Celltable实现此目的以及如何为多个列添加此箭头图标。任何线索?

1 个答案:

答案 0 :(得分:1)

您可以使用自定义标题生成器。您可以使用下面的那个(它也支持排序顺序,但如果您不需要它,可以将其删除)

public class MultiSortHeaderOrFooterBuilder<T> extends AbstractHeaderOrFooterBuilder<T> {

    private static class ColumnSortInfoHolder {
        private ColumnSortInfo columnSortInfo;
        private int sortIndex;

        public ColumnSortInfoHolder(ColumnSortInfo columnSortInfo, int sortIndex) {
            this.columnSortInfo = columnSortInfo;
            this.sortIndex = sortIndex;
        }

        public int getSortIndex() {
            return sortIndex;
        }

        public ColumnSortInfo getColumnSortInfo() {
            return columnSortInfo;
        }
    }

    private final int sortAscIconWidth;
    private final int sortAscIconHalfHeight;

    private final int sortDescIconWidth;
    private final int sortDescIconHalfHeight;

    private SafeHtml sortAscIconHtml;
    private SafeHtml sortDescIconHtml;

    private static final int ICON_PADDING = 6;

    /**
     * Create a new DefaultHeaderBuilder for the header of footer section.
     * 
     * @param table
     *            the table being built
     * @param isFooter
     *            true if building the footer, false if the header
     */

    public MultiSortHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter) {
        super(table, isFooter);

        ImageResource asc = table.getResources().sortAscending();
        ImageResource desc = table.getResources().sortDescending();
        if (asc != null) {
            sortAscIconWidth = asc.getWidth() + ICON_PADDING;
            sortAscIconHalfHeight = (int) Math.round(asc.getHeight() / 2.0);
        } else {
            sortAscIconWidth = 0;
            sortAscIconHalfHeight = 0;
        }
        if (desc != null) {
            sortDescIconWidth = desc.getWidth() + ICON_PADDING;
            sortDescIconHalfHeight = (int) Math
                    .round(desc.getHeight() / 2.0);
        } else {
            sortDescIconWidth = 0;
            sortDescIconHalfHeight = 0;
        }
    }

    @Override
    protected boolean buildHeaderOrFooterImpl() {

        AbstractCellTable<T> table = getTable();

        boolean isFooter = isBuildingFooter();
        if (isFooter)
            return false;

        // Early exit if there aren't any columns to render.
        int columnCount = table.getColumnCount();
        if (columnCount == 0) {
            // Nothing to render;
            return false;
        }

        // Early exit if there aren't any headers in the columns to render.
        boolean hasHeader = false;
        for (int i = 0; i < columnCount; i++) {
            if (table.getHeader(i) != null) {
                hasHeader = true;
                break;
            }
        }
        if (hasHeader == false) {
            return false;
        }
        HashMap<Column<?, ?>, ColumnSortInfoHolder> sortInfoByColumn = new HashMap<Column<?, ?>, ColumnSortInfoHolder>();
        // Set sorting information for multisort
        ColumnSortList sortList = table.getColumnSortList();
        if (table.getColumnSortList().size() > 0) {
            for (int colIdx = 0, sortPos = sortList.size(); colIdx < sortList.size(); colIdx++, sortPos--) {
                ColumnSortInfo columnSortInfo = sortList.get(colIdx);
                sortInfoByColumn.put(columnSortInfo.getColumn(), new ColumnSortInfoHolder(columnSortInfo, sortPos)); 
            }
        }

        // Get information about the sorted column.
        ColumnSortInfo sortedInfo = null;
        boolean isSortAscending = false;

        // Get the common style names.
        Style style = table.getResources().style();
        String className = isBuildingFooter() ? style.footer() : style.header();
        String sortableStyle = " " + style.sortableHeader();

        // Setup the first column.
        Header<?> prevHeader = getHeader(0);
        Column<T, ?> column = table.getColumn(0);
        int prevColspan = 1;
        boolean isSortable = false;
        boolean isSorted = false;
        StringBuilder classesBuilder = new StringBuilder(className);
        classesBuilder.append(" ").append(isFooter ? style.firstColumnFooter() : style.firstColumnHeader());
        if (!isFooter && column.isSortable()) {
            isSortable = true;
            sortedInfo = (sortInfoByColumn.get(column) != null) ? sortInfoByColumn.get(column).getColumnSortInfo() : null;
            isSortAscending = (sortedInfo != null) ? sortedInfo.isAscending() : false;
            isSorted = (sortedInfo != null);
        }

        // Loop through all column headers.
        TableRowBuilder tr = startRow();
        int curColumn;
        for (curColumn = 1; curColumn < columnCount; curColumn++) {

            Header<?> header = getHeader(curColumn);

            if (header != prevHeader) {
                // The header has changed, so append the previous one.
                if (isSortable) {
                    classesBuilder.append(sortableStyle);
                }
                if (isSorted) {
                    classesBuilder.append(getSortStyle(style, isSortAscending));
                }
                appendExtraStyles(prevHeader, classesBuilder);

                // Render the header.
                TableCellBuilder th = tr.startTH().colSpan(prevColspan)
                        .className(classesBuilder.toString());
                enableColumnHandlers(th, column);
                if (prevHeader != null) {
                    // Build the header.
                    Context context = new Context(0, curColumn - prevColspan, prevHeader.getKey());
                    // Add div element with aria button role
                    if (isSortable) {
                        th.attribute("role", "button");
                        th.tabIndex(-1);
                    }
                    renderRichSortableHeader(th, context, prevHeader, isSorted, isSortAscending, sortInfoByColumn);
                }
                th.endTH();

                // Reset the previous header.
                prevHeader = header;
                prevColspan = 1;
                classesBuilder = new StringBuilder(className);
                isSortable = false;
                isSorted = false;
            } else {
                // Increment the colspan if the headers == each other.
                prevColspan++;
            }

            column = table.getColumn(curColumn);
            if (!isFooter && column.isSortable()) {
                isSortable = true;
                sortedInfo = (sortInfoByColumn.get(column) != null) ? sortInfoByColumn.get(column).getColumnSortInfo() : null;
                isSortAscending = (sortedInfo != null) ? sortedInfo.isAscending() : false;
                isSorted = (sortedInfo != null);
            }
        }

        // Append the last header.
        if (isSortable) {
            classesBuilder.append(sortableStyle);
        }
        if (isSorted) {
            classesBuilder.append(getSortStyle(style, isSortAscending));
        }

        classesBuilder.append(" ").append(
                isFooter ? style.lastColumnFooter() : style.lastColumnHeader());

        appendExtraStyles(prevHeader, classesBuilder);

        // Render the last header.
        TableCellBuilder th = tr.startTH().colSpan(prevColspan).className(classesBuilder.toString());
        enableColumnHandlers(th, column);
        if (prevHeader != null) {
            Context context = new Context(0, curColumn - prevColspan, prevHeader.getKey());
            renderRichSortableHeader(th, context, prevHeader, isSorted, isSortAscending, sortInfoByColumn);
        }
        th.endTH();

        classesBuilder = new StringBuilder(style.header());
        classesBuilder.append(" ").append(style.lastColumnHeader());
        th = tr.startTH().className(classesBuilder.toString());
        th.endTH();

        // End the row.
        tr.endTR();

        return true;
    }

    /**
     * Append the extra style names for the header.
     * 
     * @param header
     *            the header that may contain extra styles, it can be null
     * @param classesBuilder
     *            the string builder for the TD classes
     */
    private <H> void appendExtraStyles(Header<H> header, StringBuilder classesBuilder) {
        if (header == null) {
            return;
        }
        String headerStyleNames = header.getHeaderStyleNames();
        if (headerStyleNames != null) {
            classesBuilder.append(" ").append(headerStyleNames);
        }
    }

    private String getSortStyle(Style style, boolean isSortAscending) {
        return isSortAscending ? style.sortedHeaderAscending() : style.sortedHeaderDescending();
    }

    /**
     * Render a header, including a sort icon if the column is sortable and
     * sorted.
     * 
     * @param out
     *            the builder to render into
     * @param header
     *            the header to render
     * @param context
     *            the context of the header
     * @param isSorted
     *            true if the column is sorted
     * @param isSortAscending
     *            indicated the sort order, if sorted
     */
    protected void renderRichSortableHeader(ElementBuilderBase<?> out,
            Context context, Header<?> header, boolean isSorted,
            boolean isSortAscending,
            HashMap<Column<?, ?>, ColumnSortInfoHolder> sortIndexByColumn) {

        AbstractCellTable<T> table = getTable();

        ElementBuilderBase<?> headerContainer = out;
        boolean posRight = LocaleInfo.getCurrentLocale().isRTL();
        int iconWidth = 0;
        int sortIndexWidth = 0;

        if (isSorted) {
            // Create an outer container to hold the icon and the header.
            iconWidth = isSortAscending ? sortAscIconWidth : sortDescIconWidth;
            int halfHeight = isSortAscending ? sortAscIconHalfHeight : sortDescIconHalfHeight;
            DivBuilder outerDiv = out.startDiv();
            StylesBuilder style = outerDiv.style().position(Position.RELATIVE).trustedProperty("zoom", "1");

            style.endStyle();

            // Add the icon.
            DivBuilder imageHolder = outerDiv.startDiv();
            style = outerDiv.style().position(Position.ABSOLUTE).top(50.0, Unit.PCT).lineHeight(0.0, Unit.PX).marginTop(-halfHeight, Unit.PX);
            if (posRight) {
                style.right(0, Unit.PX);
            } else {
                style.left(0, Unit.PX);
            }
            style.overflow(Overflow.VISIBLE).endStyle();

            imageHolder.html(getSortIcon(isSortAscending));
            imageHolder.endDiv();

            if (table.getColumnSortList().size() > 0) {

                DivBuilder sortIndexHolder = outerDiv.startDiv();
                style = sortIndexHolder.style().position(Position.ABSOLUTE).top(0.0, Unit.PCT);
                sortIndexWidth = iconWidth - 2;
                if (posRight) {
                    style.right(sortIndexWidth, Unit.PX);
                } else {
                    style.left(sortIndexWidth, Unit.PX);
                }

                Column<T, ?> column = table.getColumn(context.getColumn());
                String sortIdx = String.valueOf(sortIndexByColumn.get(column).getSortIndex());
                sortIndexHolder.html(SafeHtmlUtils.fromTrustedString(sortIdx));
                sortIndexHolder.endDiv();
            }

            // Create the header wrapper.
            headerContainer = outerDiv.startDiv();
        }

        StylesBuilder style = headerContainer.style().position(Position.RELATIVE);
        if (posRight) {
            style.paddingRight(iconWidth + sortIndexWidth + 7, Unit.PX);
        } else {
            style.paddingLeft(iconWidth + sortIndexWidth + 7, Unit.PX);
        }
        style.endStyle();

        // Build the header.
        renderHeader(headerContainer, context, header);

        // Close the elements used for the sort icon.
        if (isSorted) {
            headerContainer.endDiv(); // headerContainer.
            headerContainer.endDiv(); // outerDiv
        }
    }

    private SafeHtml getSortIcon(boolean isAscending) {
        AbstractCellTable<T> table = getTable();
        if (isAscending) {
            if (sortAscIconHtml == null) {
                AbstractImagePrototype proto = AbstractImagePrototype.create(table.getResources().sortAscending());
                sortAscIconHtml = SafeHtmlUtils.fromTrustedString(proto.getHTML());
            }
            return sortAscIconHtml;
        } else {
            if (sortDescIconHtml == null) {
                AbstractImagePrototype proto = AbstractImagePrototype.create(table.getResources().sortDescending());
                sortDescIconHtml = SafeHtmlUtils.fromTrustedString(proto.getHTML());
            }
            return sortDescIconHtml;
        }
    }
}

你这样设置

CellTable<Contact> table = new CellTable<Contact>();
table.setHeaderBuilder(new MultiSortHeaderOrFooterBuilder<TableComponent.Contact>(table, false));