Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort JFace TableViewer by Multiple Columns

Tags:

java

jface

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?

like image 700
Steffi S. Avatar asked Apr 11 '16 07:04

Steffi S.


People also ask

How do I sort all columns in excel based on one column?

Select a cell in the column you want to sort. On the Data tab, in the Sort & Filter group, click Sort. In the Sort dialog box, under Column, in the Sort by or Then by box, select the column that you want to sort by a custom list.


2 Answers

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.

like image 136
greg-449 Avatar answered Sep 22 '22 16:09

greg-449


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

like image 42
sambi reddy Avatar answered Sep 22 '22 16:09

sambi reddy