Search code examples
javaswtjfacetableviewer

AssertionFailedException on ViewerComparator constructor


I am trying to implement sorter for my TableViewer, which allows me to sort columns when I click header. However, I get this error when I try to construct my ViewerComparator :

Exception in thread "main" org.eclipse.core.runtime.AssertionFailedException: null argument:
    at org.eclipse.core.runtime.Assert.isNotNull(Assert.java:85)
    at org.eclipse.core.runtime.Assert.isNotNull(Assert.java:73)
    at org.eclipse.jface.viewers.StructuredViewer.disassociate(StructuredViewer.java:640)
    at org.eclipse.jface.viewers.AbstractTableViewer.internalRefreshAll(AbstractTableViewer.java:735)
    at org.eclipse.jface.viewers.AbstractTableViewer.internalRefresh(AbstractTableViewer.java:649)
    at org.eclipse.jface.viewers.AbstractTableViewer.internalRefresh(AbstractTableViewer.java:636)
    at org.eclipse.jface.viewers.StructuredViewer$7.run(StructuredViewer.java:1457)
    at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1392)
    at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1353)
    at org.eclipse.jface.viewers.StructuredViewer.refresh(StructuredViewer.java:1455)
    at org.eclipse.jface.viewers.ColumnViewer.refresh(ColumnViewer.java:537)
    at org.eclipse.jface.viewers.StructuredViewer.refresh(StructuredViewer.java:1414)
    at org.eclipse.jface.viewers.StructuredViewer.setComparator(StructuredViewer.java:1752)
    at gui.EMI.portfolioTab(EMI.java:283)
    at gui.EMI.open(EMI.java:112)
    at gui.EMI.main(EMI.java:58)

Here is the code :

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);
        }
    };

  // HERE IS THE PART I GET ERROR

    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);
    }
}

I called the method in below ways, same error :

aTableViewer.setComparator(new TableColumnSorter(aTableViewer));

or

TableColumnSorter sorter = new TableColumnSorter(aTableViewer);

What might be the problem here, and why is implementing a sorter to TableViewer is that hard? I literally spent hours on this and still got nothing. Seems like good old WindowsFormsApp is more powerful than SWT/JFace.


Solution

  • The error you are getting is from the refresh that setComparator does. it is not actually caused by the comparator code.

    You must use a Content Provider for the table contents when using TableViewer.

    Creating TableItems directly is not supported.

    Your assertion is because the items are not set up as expected by the viewer, using a content provider will do this properly.