Sort JFace TableViewer by Multiple Columns
Asked Answered
O

2

6

I'm pretty sure what I'm asking is impossible, but I couldn't find a definitive no to the question anywhere, so here it goes:

Consider the following working example:

public class TableViewerSorter {

private static final String DATA_COMPARATOR = "comparator";

public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());

    final TableViewer viewer = new TableViewer(shell, SWT.BORDER);
    Table table = viewer.getTable();
    table.setHeaderVisible(true);
    viewer.setContentProvider(ArrayContentProvider.getInstance());
    viewer.setSorter(new ViewerSorter() {

        @Override
        public int compare(Viewer v, Object e1, Object e2) {
            TableColumn sortColumn = table.getSortColumn();
            Comparator comparator = sortColumn == null ? null : (Comparator) sortColumn.getData(DATA_COMPARATOR);
            if (comparator != null && table.getSortDirection() == SWT.UP) {
                comparator = comparator.reversed();
            }
            return comparator == null ? 0 : comparator.compare(e1, e2);
        }
    });

    createTableViewerColumn(viewer, "ID", v -> v.ordinal());
    createTableViewerColumn(viewer, "Name", v -> v.getDisplayName());
    createTableViewerColumn(viewer, "Fruit", v -> v.isFruit());

    for (TableColumn column : table.getColumns()) {
        column.addListener(SWT.Selection, e -> {
            final Item sortColumn = table.getSortColumn();
            int direction = table.getSortDirection();

            if (column.equals(sortColumn)) {
                direction = direction == SWT.UP ? SWT.DOWN : SWT.UP;
            } else {
                table.setSortColumn(column);
                direction = SWT.UP;
            }
            table.setSortDirection(direction);
            viewer.refresh();
        });
    }
    viewer.setInput(Value.values());

    shell.pack();
    shell.open();

    while (!shell.isDisposed()) {
        if (!display.readAndDispatch()) {
            display.sleep();
        }
    }
    display.dispose();
}

private static <T extends Comparable<T>> TableViewerColumn createTableViewerColumn(TableViewer viewer, String name,
        Function<Value, T> propertyFunction) {
    TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
    viewerColumn.setLabelProvider(new ColumnLabelProvider() {
        @Override
        public String getText(Object element) {
            return propertyFunction.apply((Value) element).toString();
        }
    });

    TableColumn column = viewerColumn.getColumn();
    column.setText(name);
    column.setWidth(100);
    column.setData(DATA_COMPARATOR, (Comparator<Value>) (v1, v2) -> propertyFunction.apply(v1).compareTo(propertyFunction.apply(v2)));
    return viewerColumn;
}

static enum Value {
    APPLE, BANANA, CABBAGE, DILL, EGGPLANT;

    String getDisplayName() {
        return name().substring(0, 1) + name().substring(1).toLowerCase();
    }

    boolean isFruit() {
        return this != CABBAGE && this != DILL;
    }
}

static class LabelProvider<T> extends ColumnLabelProvider {

    private final Function<T, String> toStringFunction;

    public LabelProvider(final Function<T, String> toStringFunction) {
        this.toStringFunction = toStringFunction;
    }

    @Override
    public String getText(final Object element) {
        return element == null ? null : this.toStringFunction.apply((T) element);
    }

}
}

What I want is for the user to click the second column then the third, and have the input sorted by the third column, and when the values are equal, by the second.

Of course I can just add a list of clicked columns to the ViewerSorter, or (depending on the sorting algorithm) just use the last sorted list of elements as a base for sorting instead of the viewer's input.

That's the easy part.

The hard part is how to communicate to the user that this particular table is sorted by two columns. The API seems to not support the use case, but I want to make sure: Is it possible for JFace tables to be sorted by multiple columns? If so, how?

Outmoded answered 11/4, 2016 at 7:10 Comment(0)
A
3

There is currently no standard way to indicate multiple sort columns. There is a long standing bug 133154 requesting support for multiple setSortColumm columns but nothing has ever been done.

Alberto answered 11/4, 2016 at 8:38 Comment(0)
P
2

Yes. greg-449 is correct that there is no standard implementation so far. If you are really keen on some how get it working, I have a workaround by using TableColumn.setImage(image),set correct sort image on column . Maintain sort order in TableColumn.setData(key,value) and all sorted columns in Table.setData(key,value) and never use or set Table.setSortDirection(direction) and Table.setSortColumn().

enter image description here

Pastis answered 15/4, 2016 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.