JFace table sorting

Nowadays, when the application displays as a table, the modern user expects to click on the the column header to change the ordering criteria. Unfortunately, SWT/JFace API have not yet implemented this feature transparently. The programmer is required to write a bunch of code to implement this feature on each table.
For this purpose, I have written a single class that listens to table columns and applies ordering to the table viewer.

This class sorts table data according the the string representation of the cells. Sure, there is still much to be improved on this code, but let me present it as an advice.


import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

public class TableColumnSorter extends ViewerComparator {
	public static final int ASC = 1;
	public static final int NONE = 0;
	public static final int DESC = -1;

	private int direction = 0;
	private TableColumn column = null;
	private int columnIndex = 0;
	final private TableViewer viewer;
	
	final private SelectionListener selectionHandler = new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			TableColumnSorter sorter = (TableColumnSorter) TableColumnSorter.this.viewer.getComparator();
			Assert.isTrue(TableColumnSorter.this == sorter);
			TableColumn selectedColumn = (TableColumn) e.widget;
			Assert.isTrue(TableColumnSorter.this.viewer.getTable() == selectedColumn.getParent());
			TableColumnSorter.this.setColumn(selectedColumn);
		}
	};
	
	public TableColumnSorter(TableViewer viewer) {
		this.viewer = viewer;
		Assert.isTrue(this.viewer.getComparator() == null);
		viewer.setComparator(this);
		
		for (TableColumn tableColumn : viewer.getTable().getColumns()) {
			tableColumn.addSelectionListener(selectionHandler);
		}
	}

	public void setColumn(TableColumn selectedColumn) {
		if (column == selectedColumn) {
			switch (direction) {
			case ASC:
				direction = DESC;
				break;
			case DESC:
				direction = ASC;
				break;
			default:
				direction = ASC;
				break;
			}
		} else {
			this.column = selectedColumn;
			this.direction = ASC;
		}

		Table table = viewer.getTable();
		switch (direction) {
		case ASC:
			table.setSortColumn(selectedColumn);
			table.setSortDirection(SWT.UP);
			break;
		case DESC:
			table.setSortColumn(selectedColumn);
			table.setSortDirection(SWT.DOWN);
			break;
		default:
			table.setSortColumn(null);
			table.setSortDirection(SWT.NONE);
			break;
		}

		TableColumn[] columns = table.getColumns();
		for (int i = 0; i < columns.length; i++) {
			TableColumn theColumn = columns[i];
			if (theColumn == this.column) columnIndex = i;
		}
		viewer.setComparator(null);
		viewer.setComparator(this);
	}

	@Override
	public int compare(Viewer viewer, Object e1, Object e2) {
		return direction * doCompare(viewer, e1, e2);
	}

	protected int doCompare(Viewer v, Object e1, Object e2) {
       Assert.isTrue(viewer == this.viewer);
       ILabelProvider labelProvider = (ILabelProvider) viewer.getLabelProvider(columnIndex);
		String t1 = labelProvider.getText(e1);
		String t2 = labelProvider.getText(e2);
		if (t1 == null) t1 = "";
		if (t2 == null) t2 = "";
		return t1.compareTo(t2);
	}
}

One Response to JFace table sorting

  1. wtrocki says:

    In: Assert.isTrue(viewer == this.viewer);
    we comparing identical objects. Should be changed to:
    Assert.isTrue(v == this.viewer);

    Here should be break in for loop:
    for (int i = 0; i < columns.length; i++) {
    TableColumn theColumn = columns[i];
    if (theColumn == this.column){
    columnIndex = i;
    break;
    }
    }

    And last big problem:
    viewer.setComparator(null);
    viewer.setComparator(this);

    should be changed to viewer.refresh()
    (only if we have unchanged table)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: