Reputation: 343
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
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