On Sun, 23 May 2021 10:13:48 GMT, Jeanette Winzenburg <faste...@openjdk.org> 
wrote:

>> Michael Strauß has updated the pull request with a new target base due to a 
>> merge or a rebase. The pull request now contains 10 commits:
>> 
>>  - Merge branch 'master' into fixes/JDK-8196065
>>    
>>    # Conflicts:
>>    # 
>> modules/javafx.controls/src/test/java/test/javafx/scene/control/MultipleSelectionModelImplTest.java
>>  - Merge branch 'master' into fixes/JDK-8196065
>>  - Merge branch 'master' into fixes/JDK-8196065
>>    
>>    # Conflicts:
>>    # 
>> modules/javafx.controls/src/main/java/javafx/scene/control/ControlUtils.java
>>  - Cleanup
>>  - Fixed clear-and-select change notification
>>  - Add failing tests
>>  - Cleanup
>>  - Added tests
>>  - Fix incorrect index when multiple remove changes are handled in 
>> SelectedItemsReadOnlyObservableList
>>  - Add failing test
>
> modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/SelectedItemsReadOnlyObservableList.java
>  line 54:
> 
>> 52:             while (c.next()) {
>> 53:                 if (c.wasReplaced()) {
>> 54:                     List<E> removed = getRemovedElements(c, 
>> totalRemovedSize);
> 
> hmm, don't quite understand all the fuss (but might be overlooking something, 
> has been a while since I did a deeper dig into the selection issues ;) 
> 
> - we have a copy of the items (itemsRefs) with the same coordinates we 
> receive from the change
> - this list is in sync with the indices, that is it contains the items at the 
> respective selectedIndices
> - currently, that's done in a bulk setting at the end of the listener code
> 
> Why not sync our copy while working through the change? Doing so, would 
> automatically collect the state of our own change, or what am I missing?

This was my first thought, too. However, it doesn't work because 
`SelectedItemsReadOnlyObservableList` doesn't truthfully report its changes, so 
we can't simply replay its reported changes onto our copy of the items list. 
For example, consider the following simple piece of code:


ListView<String> listView = new 
ListView<>(FXCollections.observableArrayList("foo", "bar"));
MultipleSelectionModel<String> model = listView.getSelectionModel();
model.setSelectionMode(SelectionMode.SINGLE);
model.getSelectedIndices().addListener((ListChangeListener<? super 
Integer>)System.out::println);
model.select(0);
model.select(1);


You'd expect the following output:

{ [0] added at 0 }
{ [0] replaced by [1] at 0 }


However, the actual output is:

{ [0] added at 0 }
{ [1] added at 0 }


While that is a bug, it almost seems like it is a bug _by design_. 
`MultipleSelectionModelBase` actually contains lots of code to suppress change 
notifications. In this particular example, a crucial change notification is 
suppressed in `MultipleSelectionModelBase:405`:

if (getSelectionMode() == SINGLE) {
    startAtomic();
    quietClearSelection();
    stopAtomic();
}
selectedIndices.set(row);


The reason why `MultipleSelectionModelBase` interferes with `selectedIndices` 
change notifications is to prevent surfacing all kinds of invalid intermediate 
selection states.

I tried to fix this by making `selectedIndices` changes transactional, where 
each of the `MultipleSelectionModel` operations would be a transaction that 
silently accumulates changes (clear, set, and so on), and at the end of a 
transaction, the changes would be distilled down into a single change 
notification.

However, in doing so, I ended up rewriting large parts of 
`MultipleSelectionModelBase`. This seemed like too big of a change. Also, I 
noticed that at one point you prototyped a new implementation of 
`SelectionModel`... maybe starting from scratch is better than adding 
transactions on top of the existing implementation.

> modules/javafx.controls/src/test/java/test/com/sun/javafx/scene/control/SelectedItemsReadOnlyObservableListTest.java
>  line 120:
> 
>> 118:         assertEquals(change(replaced(0, range("foo"), range("bar"))), 
>> changes.get(0));
>> 119:     }
>> 120: 
> 
> Another thingy I don't quite understand, sry ;) 
> 
> What do you want to test here? We have:
> 
> selectedItems before: [foo, bar]
> selectedItems after: [bar, foo]
> 
> so we need a change (the "should be" snippet in the description of this 
> method)
> 
> replaced [foo, bar] by [bar, foo] at 0  
> 
> we get: 
> 
> replaced [foo] by [bar] at 0
> 
> which is an incorrect notification (because it's incomplete, doesn't notify 
> at all about the replace at 1) covered by a passing test .. feels fishy. The 
> other way round: if selectedItems cannot react to such a use-case with a 
> correct notification, it might be broken?

Yes, `selectedItems` is broken. I agree that having an objectively incorrect 
test pass is fishy, but the alternative would be to not have the test at all, 
and lose the "free" heads-up if at some point in the future the underlying 
issue is fixed. Do you think it's better to have the correct test, but ignore 
it?

-------------

PR: https://git.openjdk.java.net/jfx/pull/478

Reply via email to