18

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)?

ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • What is the concrete type of the ObservableList you are using? Looks like ListProperty is an abstract class that does not declare setAll(...) – Zeki Dec 02 '14 at 14:48
  • @zeki hmm .. all ObservableLists must have a setAll(T... item) - can be unsupported, of course, so take any that has it implemented (ListProperty is nothing special, it simply routes the setAll of its backing list) – kleopatra Dec 02 '14 at 16:08
  • In that case, could you extend ListProperty and have setAll trigger an event before calling the super method? – Zeki Dec 02 '14 at 16:12
  • @Zeki hmm .. looks like my question isn't overly clear (will try to reword it tomorrow :-) - my perspective if from the listener, just seeing the changes without any control over the sender. – kleopatra Dec 02 '14 at 17:30
  • @downvoter - care to explain? – kleopatra Dec 03 '14 at 16:02
  • @kleopatra:I don't understand your question. Especially assertEquals(0, c.getFrom());? Can you elaborate? – Micromega Dec 03 '14 at 20:15
  • @kleopatra:Why not clear the delete/list? – Micromega Dec 03 '14 at 20:53
  • @Phpdna I'm the listener - don't want to change the list itself, just do something if all content was swapped out. As to the c.getFrom(): a setAll fires a replaced starting at 0 – kleopatra Dec 03 '14 at 22:56
  • @kleopatra:IMO the core code is safer. It guarantees the list is the same. Or can you use the core code and your solution parallel? – Micromega Dec 03 '14 at 23:25

1 Answers1

4

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.

eckig
  • 10,964
  • 4
  • 38
  • 52
  • ahhh ... didn't even think at looking into core implementation ;-) Good argument, thanks! clear/setAll being the same is good enough - basically I need some means to reliably throw away all state related to old items (without having references to the items, only to their former positions). hmm ... back to thinking – kleopatra Dec 10 '14 at 11:00
  • And ListChangeListener.Change.getRemoved() / getFrom() / getTo() is not good enough for cleaning up? – eckig Dec 10 '14 at 11:49
  • hmm .. not if I follow core implementations of selectionModels. Which are buggy as hell, though. Probably need to think from scratch, maybe setAll is not such a special case, after all :-) – kleopatra Dec 10 '14 at 14:11