semTex
semTex

Reputation: 343

Disable ContextMenu with dependency to TreeTableView selection

I have a TreeTableView which allows multiselection. I got a ContextMenu for editing or deleting that selected items.

Delete and edit should only be enabled if there is at least one selection.

final BooleanBinding isTableSelectionEmpty = Bindings.isEmpty(this.table.getSelectionModel().getSelectedItems());
this.menuItemDelete.disableProperty().bind(isTableSelectionEmpty);

That is working as expected.

But now I have dependencies on different values of the selected rows. Like for example that the row is system-mandatory and should not be deleted.

I tried the following but it is not working

final BooleanBinding invalidSelection = Bindings.and(Bindings.isEmpty(tableSelection),
                Bindings.isNotEmpty(tableSelection.filtered(item -> {
                    this.logger.trace("filtering :" + item);
                    return item.getValue().getSystemProperty().get();
                })));
this.menuItemDelete.disableProperty().bind(invalidSelection);

Not even the debug-trace is printed and the value of the binding is always false (thus enabling the menu item). Now I am a bit lost. Where is my mistake?

Upvotes: 1

Views: 60

Answers (1)

fabian
fabian

Reputation: 82461

FilteredList relies on a correct ListIterator, but currently there is a bug in the ListIterator the selectedItems list in MultipleSelectionModelBase. This prevents the filtering to properly work. To fix this you could create a ObservableList implementation delegating everything but the ListIterator creation to a source ObservableList. Most IDEs have a functionality to generate this kind of methods automatically, reducing the amount of work to a minimum (e.g.in NetBeans: Generate -> Delegate Method).

public class ObservableListIteratorFix<T> implements ObservableList<T> {

    private final ObservableList<T> list;

    public ObservableListIteratorFix(ObservableList<T> list) {
        this.list = list;
    }

    @Override
    public void addListener(ListChangeListener<? super T> listener) {
        list.addListener(listener);
    }

    @Override
    public void removeListener(ListChangeListener<? super T> listener) {
        list.removeListener(listener);
    }

    @Override
    public boolean addAll(T... elements) {
        return list.addAll(elements);
    }

    ...

    private class CustomListIterator implements ListIterator<T> {
        private final ListIterator<T> iterator;
        private int index;

        public CustomListIterator(int index) {
            this.iterator = list.listIterator(index);
            this.index = index;
        }

        @Override
        public boolean hasNext() {
            return iterator.hasNext();
        }

        @Override
        public T next() {
            T t = iterator.next();
            index++;
            return t;
        }

        @Override
        public boolean hasPrevious() {
            return iterator.hasPrevious();
        }

        @Override
        public T previous() {
            T t = iterator.previous();
            index--;
            return t;
        }

        @Override
        public int nextIndex() {
            return index;
        }

        @Override
        public int previousIndex() {
            return index-1;
        }

        @Override
        public void remove() {
            iterator.remove();
        }

        @Override
        public void set(T e) {
            iterator.set(e);
        }

        @Override
        public void add(T e) {
            iterator.add(e);
        }

        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            iterator.forEachRemaining(action);
        }

    }

    @Override
    public ListIterator<T> listIterator() {
        return listIterator(0);
    }

    @Override
    public ListIterator<T> listIterator(int index) {
        return new CustomListIterator(index);
    }

    @Override
    public FilteredList<T> filtered(Predicate<T> predicate) {
        return new FilteredList<>(this, predicate);
    }

    ...

This allows you to use the class as wrapper the selectedItems which should fix the filtering...

new ObservableListIteratorFix<>(tableSelection).filtered(...)

Upvotes: 2

Related Questions