Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObservableList: how to reliably detect a setAll?

In some contexts it's necessary to detect - in a ListChangeListener, without control about the list itself - a "all data swapped out", f.i. when we need to clear some state like selection - on completely new data the old state is meaningless.

Completely new data can be reached by

  • list.setAll(...)
  • list.set(otherObservableList) if list is a ListProperty

Thinking about which type of changes could be fired on setAll (c is the change, items is the observed list, "subChangeCount" pseudo-code for counting the subchanges):

// initially empty
assertEquals(0, items.size());
items.setAll(1, 2, 4);
assertEquals(1, c.subChangeCount());
assertTrue(c.wasAdded() && !c.wasReplaced());
assertEquals(0, c.getFrom());
assertEquals(c.getList().size(), c.getAddedSize()); 

// initially not empty
assertTrue(items.size() > 0);
items.setAll(1, 2, 4);
assertEquals(1, c.subChangeCount());
assertTrue(c.wasReplaced());
assertEquals(0, c.getFrom());
assertEquals(c.getList().size(), c.getAddedSize()); 

This seems to allow a utility check like:

boolean wasSetOrClearedAll(Change c) {
   if (c.getList().isEmpty()) return true;
   c.next();
   if (c.getAddedSize() == c.getList().size()) return true; 
   return false; 
}  

In contrast, internal fx code, f.i. in listening to ComboBox' items:

while (c.next()) {
   comboBox.wasSetAllCalled = comboBox.previousItemCount == c.getRemovedSize();
   ... 
}
comboBox.previousItemCount = getItemCount();

stores the old itemCount and compare that against the current removedSize (which I'm uncomfortable with, old state gets stale far too often for my taste), nevertheless there's a good probability that I'm missing something with my approach.

Question is:

in which context would my utility method fail (and core approach would detect the setAll correctly)?

like image 442
kleopatra Avatar asked Nov 18 '14 12:11

kleopatra


1 Answers

Unfortunately there is no reliable way of detecting this on the Listener side.

The struggle starts with the default implemention, which mostly looks like this:

@Override
public boolean setAll(Collection<? extends E> col) {
    beginChange();
    try {
        clear();
        addAll(col);
    } finally {
        endChange();
    }
    return true;
}

If you pass an empty Collection to setAll the result and the event that is fired are both exactly the same as when you would have called clear.

So your method wasSetOrClearedAll returns true when clear has been called, too (as would the core implementation).

So in the end there is no generic detection of setAll, it all depends on your use-case. If you can narrow down what you are trying to detect you may write a filter for that.

like image 153
eckig Avatar answered Nov 19 '22 12:11

eckig