Search code examples
nattable

NatTable filtering row header layer for dynamic list


When I use dynamic list for Nattable the filtering via filter header layer it does not work for me. I want to be able to filter all columns. I have respective code for each column in the filter row configuration class and it works if the input is a static list.

Attached my code snippet:

public Control createPeopleTable(Composite parent) {

    // create a new ConfigRegistry which will be needed for GlazedLists
    configRegistry = new ConfigRegistry();
    peopleTableColumns = PeopleTableColumnDefinition.getPeopleTableColumns();

    final Map<String, String> propertyToLabelMap = new HashMap<>();
    final String[] propertyNames = new String[peopleTableColumns.size()];
    for (int i = 0; i < peopleTableColumns.size(); ++i) {
        final PeopleTableColumnDefinition col = peopleTableColumns.get(i);
        propertyNames[i] = col.getProperty();
        propertyToLabelMap.put(propertyNames[i], col.getDisplayName());
    }

    columnPropertyAccessor = new ExtendedReflectiveColumnPropertyAccessor<>(propertyNames);columnPropertyAccessor = new ExtendedReflectiveColumnPropertyAccessor<>(propertyNames);

    peopleList = new ArrayList<>();
    eventList = GlazedLists.eventList(peopleList);
    dynamicValues = GlazedLists.threadSafeList(eventList);
    bodyLayerStack = new BodyLayerStack(dynamicValues, columnPropertyAccessor);
    .....

    IFilterStrategy<People> filterStrategy = new DefaultGlazedListsFilterStrategy<>(
            bodyLayerStack.getFilterList(), columnPropertyAccessor, configRegistry);
    // Note: The column header layer is wrapped in a filter row composite.
    // This plugs in the filter row functionality
    FilterRowHeaderComposite<People> filterRowHeaderLayer = new FilterRowHeaderComposite<>(filterStrategy,
            sortHeaderLayer, bodyLayerStack.getBodyDataProvider(), configRegistry);

    // build the row header layer
    IDataProvider rowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyLayerStack.getBodyDataProvider());
    DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
    ILayer rowHeaderLayer = new RowHeaderLayer(rowHeaderDataLayer, bodyLayerStack,
            bodyLayerStack.getSelectionLayer());

    // build the corner layer
    IDataProvider cornerDataProvider = new DefaultCornerDataProvider(columnHeaderDataProvider,
            rowHeaderDataProvider);
    DataLayer cornerDataLayer = new DataLayer(cornerDataProvider);
    cornerLayer = new CornerLayer(cornerDataLayer, rowHeaderLayer, filterRowHeaderLayer);

    // build the grid layer
    GridLayer gridLayer = new GridLayer(bodyLayerStack, filterRowHeaderLayer, rowHeaderLayer, cornerLayer);

    // turn the auto configuration off as we want to add our header menu
    // configuration
    natTable = new NatTable(parent, gridLayer, false);


    .....

    natTable.addConfiguration(new FilterRowConfiguration());
    natTable.configure();
    ...

    return natTable;

}

    class FilterRowConfiguration extends AbstractRegistryConfiguration {

    @Override
    public void configureRegistry(IConfigRegistry configRegistry) {


        // register the FilterRowTextCellEditor in the first column which
        // immediately commits on key press
        configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new FilterRowTextCellEditor(),
                DisplayMode.NORMAL, FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX
                        + PeopleTableColumnDefinition.Name.columnIndex());

        .....
    }


    class BodyLayerStack extends AbstractLayerTransform {

    private FilterList<People> filterList;
    private final SelectionLayer selectionLayer;
    private SortedList<People> sortedList;
    private ViewportLayer viewportLayer;

    public BodyLayerStack(EventList<People> values,
            IColumnPropertyAccessor<People> columnPropertyAccessor) {

        // use the SortedList constructor with 'null' for the Comparator
        // because the Comparator
        // will be set by configuration
        sortedList = new SortedList<>(values, null);
        // wrap the SortedList with the FilterList
        filterList = new FilterList<>(sortedList);

        peopleListDataProvider = new PeopleListDataProvider<>(filterList, columnPropertyAccessor);
        bodyDataLayer = new DataLayer(peopleListDataProvider);


        final ColumnOverrideLabelAccumulator columnLabelAccumulator = new ColumnOverrideLabelAccumulator(
                bodyDataLayer);
        for (int i = 0; i < peopleTableColumns.size(); i++) {
            PeopleTableColumnDefinition peopleTableColumnDefinition = peopleTableColumns.get(i);
            columnLabelAccumulator.registerColumnOverrides(i, peopleTableColumnDefinition.getTableLabel());
        }
        bodyDataLayer.setConfigLabelAccumulator(columnLabelAccumulator);

        // layer for event handling of GlazedLists and PropertyChanges
        GlazedListsEventLayer<People> glazedListsEventLayer = new GlazedListsEventLayer<>(bodyDataLayer,
                filterList);

        selectionLayer = new SelectionLayer(glazedListsEventLayer);
        viewportLayer = new ViewportLayer(selectionLayer);
        FreezeLayer freezeLayer = new FreezeLayer(selectionLayer);
        compositeFreezeLayer = new CompositeFreezeLayer(freezeLayer, viewportLayer, selectionLayer);
        setUnderlyingLayer(compositeFreezeLayer);
    }

    public SortedList<People> getSortedList() {
        return sortedList;
    }

    public SelectionLayer getSelectionLayer() {
        return this.selectionLayer;
    }

    public FilterList<People> getFilterList() {
        return this.filterList;
    }

    public PeopleListDataProvider<People> getBodyDataProvider() {
        return peopleListDataProvider;
    }
}

public void setListOfPeople(List<People> listOfPeople) {

    this.eventList.getReadWriteLock().writeLock().lock();
    this.dynamicValues.getReadWriteLock().writeLock().lock();
    try {
        peopleList.clear();
        eventList.clear();
        dynamicValues.clear();
        peopleList.addAll(listOfPeople);
        eventList.addAll(listOfPeople);
        dynamicValues.addAll(listOfPeople);
        peopleListDataProvider.setPeopleList(peopleList);
    } finally {
        eventList.getReadWriteLock().writeLock().unlock();
        dynamicValues.getReadWriteLock().writeLock().unlock();
    }
}

Solution

  • It seems you haven't understood the principles of GlazedLists and Java object references.

    First you don't have to call clear() and addAll() on all lists. The GlazedLists are views on the base list, so it should be enough to call on the EventList or a higher list like the FilterList. Second mistake is that you set another list on the IDataProvider. And that list is not the FilterList. So actually you disable the filter as the FilterList is doing the filter magic. And setting the list is not necessary as you performed a list modification. So why changing it then?