Re: RFR: 8138842: TableViewSelectionModel.selectIndices does not select index 0 [v2]

2023-02-05 Thread Karthik P K
On Mon, 6 Feb 2023 06:28:39 GMT, Ajit Ghaisas  wrote:

>> Karthik P K has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   Fix first index selection issue in TreeTableView
>
> Looks good to me.

@aghaisas please sponsor this PR.

-

PR: https://git.openjdk.org/jfx/pull/1018


Re: Feedback requested for infrastructure for properties that wish to delay registering listeners

2023-02-05 Thread John Hendrikx



On 06/02/2023 06:00, Michael Strauß wrote:

I like your proposal in general, since it may result in a performance
improvement in some cases. If we can avoid to eagerly registering
listeners that aren't needed, that's great.
Thanks. It would probably simplify some cases that now require custom 
property implementations.

However, it is not an alternative to using weak listeners. Consider
the following test, which is taken from Florian's PR
(https://github.com/openjdk/jfx/pull/689):

 @Test
 public void testListPropertyLeak2() {
JMemoryBuddy.memoryTest(checker -> {
ObservableList list = FXCollections.observableArrayList();
ListProperty listProperty = new SimpleListProperty<>(list);

checker.setAsReferenced(list);
checker.assertCollectable(listProperty);
});
 }

This test only passes with your PR because `listProperty` doesn't
register a listener on `list` (that's what you are proposing, after
all).


Yes, when creating a new instance of something (in this case 
`SimpleListProperty`) there shouldn't be any weird side effects. 
Registering a listener to something else in the constructor is passing 
on a reference to the instance (SimpleListProperty) before it is fully 
constructed, which is a bad practice.  Because it is bad practice, it is 
very rare to see an object creation have side effects, like it being 
registered somewhere, that would block its immediate garbage collection.


A call to `new` without an assignment to a variable, will in almost all 
cases result in that object being immediately eligible for GC. This is 
what users expect, the only one that has a reference to the object 
resulting from a `new` operator is the caller.  The cases where this 
doesn't happen are likely bugs or not idiomatic Java.  This escapes are 
problematic for various reasons (see recent discussions in amber-dev and 
the new this-escape warning).  In the strictly threaded environment of 
JavaFX you can get away with it usually, but not always.  It is still a 
huge surprise for users that expect the `new` operator to be side effect 
free.


This is why I applaud the effort which we're doing for Skins at the 
moment, moving all listener registration to the `install` method, 
preventing the instance from escaping before it is fully constructed.  
It means that just constructing the Skin does not tie it to a control 
already.  Similarly, just constructing a ListProperty should not tie it 
to an ObservableList; it doesn't matter if that tie is strong or weak.



As soon as you do that, for example by adding the following line, the
test fails:

 listProperty.addListener((ListChangeListener) change -> 
{});

But the test shouldn't ever fail, because the ObservableList that is
wrapped by ListProperty should never keep a strong reference to the
ListProperty, even if the ListProperty is itself observed.
Why should it work that way?  The alternative is that my listener is 
discarded without my knowledge.  There is no warning in my IDE, in my 
logs, or anywhere.  It just seems to work, and then breaks at some point 
in the future. The fact that it seems to work, but then doesn't is a 
huge problem for debugging, testing and reproducing user problems. That 
last one is nasty, because it may work on my machine; when weak 
references get cleared can depend on JVM used, JVM parameters, memory 
available, hardware platform, etc.. -- they're fine for low level work 
like caching, but using them in a high level mechanism like a UI is 
making JavaFX far more complex than it should be.

That's a bug in the current implementation, and hiding it by making it
contingent upon the presence of observers doesn't fix the underlying
issue.


I don't think it's a bug.  I took an action to register a listener.  It 
is on me to take action to unregister it.  And until that time it should 
keep working.


I mean, what if Java were to decide that a `Thread` which I started is 
not doing relevant work because it determined that the objects the 
thread is using are not referenced by any other threads?  Should it be 
allowed to kill this `Thread`? And if that's allowed, should it do this 
silently without warning?


What if I added an important listener like this:

permissionsListProperty.addListener(AuditingService::auditLogPermissionChanges);

Do you think JavaFX should decide that this is not relevant because only 
the property still has a reference to this listener, but nothing else has?


Also, do you think it should keep working until a garbage collection 
occurs, but then stop working after one occurs?  When will that be?


I feel there is fundamental misunderstanding of how listeners are 
normally working in Java. JavaFX is the only system that decides that a 
listener is irrelevant based on how it is being referenced.  Nothing 
else does this.  Beans don't do this (PropertyChangeListener), other UI 
frameworks don't do this (Swing, AWT, SWT), event frameworks I worked 

Re: RFR: 8138842: TableViewSelectionModel.selectIndices does not select index 0 [v2]

2023-02-05 Thread Ajit Ghaisas
On Wed, 1 Feb 2023 06:37:21 GMT, Karthik P K  wrote:

>> In `selectIndices` method, zero length array is not considered while 
>> ignoring row number given as parameter.
>> 
>> Updated the code to consider both null and zero length array in the 
>> condition before ignoring the row value given as parameter.
>> 
>> Added unit test to validate the fix
>
> Karthik P K has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Fix first index selection issue in TreeTableView

Looks good to me.

-

Marked as reviewed by aghaisas (Reviewer).

PR: https://git.openjdk.org/jfx/pull/1018


Re: Feedback requested for infrastructure for properties that wish to delay registering listeners

2023-02-05 Thread Michael Strauß
I like your proposal in general, since it may result in a performance
improvement in some cases. If we can avoid to eagerly registering
listeners that aren't needed, that's great.

However, it is not an alternative to using weak listeners. Consider
the following test, which is taken from Florian's PR
(https://github.com/openjdk/jfx/pull/689):

@Test
public void testListPropertyLeak2() {
   JMemoryBuddy.memoryTest(checker -> {
   ObservableList list = FXCollections.observableArrayList();
   ListProperty listProperty = new SimpleListProperty<>(list);

   checker.setAsReferenced(list);
   checker.assertCollectable(listProperty);
   });
}

This test only passes with your PR because `listProperty` doesn't
register a listener on `list` (that's what you are proposing, after
all).
As soon as you do that, for example by adding the following line, the
test fails:

listProperty.addListener((ListChangeListener) change -> {});

But the test shouldn't ever fail, because the ObservableList that is
wrapped by ListProperty should never keep a strong reference to the
ListProperty, even if the ListProperty is itself observed.
That's a bug in the current implementation, and hiding it by making it
contingent upon the presence of observers doesn't fix the underlying
issue.


On Sun, Feb 5, 2023 at 10:46 AM John Hendrikx  wrote:
>
> Any comments on this?
>
> I think having API to make it easier for both JavaFX and users to create
> listeners that can delay registration to their own dependencies. This
> would be an alternative to using weak listeners for these cases.
>
> --John


Re: RFR: 8290310: ChangeListener events are incorrect or misleading when a nested change occurs [v2]

2023-02-05 Thread John Hendrikx
On Tue, 3 Jan 2023 09:42:05 GMT, John Hendrikx  wrote:

>> This contains the following:
>> - Nested changes or invalidations using ExpressionHelper are delayed until 
>> the current emission completes
>>   - This fixes odd change events being produced (with incorrect oldValue)
>>   - Also fixes a bug in ExpressionHelper where a nested change would unlock 
>> the listener list early, which could cause a 
>> `ConcurrentModificationException` if a nested change was combined with a 
>> remove/add listener call
>> - A test for ExpressionHelper to verify the new behavior
>> - A test for all *Property and *Binding classes that verifies correct 
>> listener behavior at the API level (this tests gets 85% coverage on 
>> ExpressionHelper on its own, the only thing it is not testing is the locking 
>> behavior, which is not relevant at the API level).
>> - A fix for `WebColorFieldSkin` which triggered a nested change which used a 
>> flag to prevent an event loop (I've changed it now to match how 
>> `DoubleFieldSkin` and `IntegerFieldSkin` do it
>
> John Hendrikx has updated the pull request with a new target base due to a 
> merge or a rebase. The pull request now contains two commits:
> 
>  - Merge branch 'master' of https://git.openjdk.org/jfx into 
> feature/delayed-nested-emission
>  - Delay nested event emission

> The fix for the bug with nested events releasing the lock seems fine. I'm 
> still not sure if the behavioral change is what we want the result to be even 
> if it's better than what we have now. I have mentioned this in [#108 
> (comment)](https://github.com/openjdk/jfx/pull/108#issuecomment-590878643). 
> we need to decide on a spec first, and there are several facets to it as 
> discussed in the mailing list link above ([#837 
> (review)](https://github.com/openjdk/jfx/pull/837#pullrequestreview-1233910264)).

Is there any doubt as to what the old value should be?  I think this is a bug 
fix only, and although I think it is good to discuss the whole listener system, 
I think we shouldn't delay this fix too much.

After all, it is a very common pattern to use the old value for unregistering 
listeners when listening to a property chain (like node -> scene), and if the 
"old property" is ever incorrect, then the `removeListener` call will silently 
fail (shame we can't change that any more).
 
> I will re-summarize what I think needs to be defined before implementing a 
> behavior change like the one proposed here:

I don't think this is a behavior change, it is a bug fix, unless we document 
that `ChangeListener` old value is a "best effort value" that cannot be trusted 
to contain anything useful when nested changes occur.  Nested changes can 
easily occur in the huge web of properties that are sometimes woven (take the 
layout code for example).

> ### Listener order
> When listeners are registered, they are added to some collection (an array, 
> currently). The add/remove methods hint at an order, but don't guarantee one. 
> Do we specify an order, or say it's unspecified?

I think it is too late to change anything significant here.  Also the primary 
reason we've been pushing for a change here is I think the poor (remove) 
performance when there are many listeners.  However, I think having many 
listeners on a single property is always an unwanted situation.  The remove 
performance is simply the first problem you'll encounter.  The next problem 
you'll encounter is when 10.000+ listeners need to be notified of a change... 
it will quickly become unworkable.

Furthermore, there are data structures that have `O(1)` add(end) + remove(T) 
performance and `O(n)` iterate performance, while still being sequential and 
allowing duplicates.  The remove "problem" could be solved that way without 
breaking existing code, but that will not speed up notification (which will be 
your next problem).  I've mostly abandoned fixes in this area as I think it is 
**never** a good idea to have so many listeners that remove performance becomes 
an issue.

So, if it were up to me, and I'm pretty convinced this is going to break quite 
some code out there, I'd say it should be:

- listeners are called in the order they're registered
- duplicates are allowed
- removing a listener removes the first instance of that listener (not the last 
or a random one)

Since there are data structures that can handle the requirements we need (we 
only need add-at-end, remove(T) and iteration) I think we're not locking 
ourselves into too much problems (the cost of such a data structure is slower 
get(index) and remove(index) performance, but we don't need these). 

> ### Event dispatch order
> The order in which listeners are triggered is not necessarily the order of 
> the listeners above. Do we specify a dispatch order, or say it's unspecified? 
> If it's specified, the listener order is probably also specified.

I'll consider this the same problem, with the same risks, see above.

> We are also dispatching invalidation events be

Re: RFR: JDK-8298528: Clean up raw type warnings in base in bindings and collections packages [v2]

2023-02-05 Thread Nir Lisker
On Sun, 1 Jan 2023 16:08:15 GMT, John Hendrikx  wrote:

>> Packages fixed:
>> - com.sun.javafx.binding
>> - com.sun.javafx.collections
>> - javafx.beans
>> - javafx.beans.binding
>> - javafx.collections
>> - javafx.collections.transformation
>
> John Hendrikx has updated the pull request incrementally with two additional 
> commits since the last revision:
> 
>  - Clean up expression classes repeated null checks
>  - Use instanceof with pattern matching in a few spots

I looked at it again. I think it would be best to do the sorting-related 
changes separately. The rest looks good.

-

PR: https://git.openjdk.org/jfx/pull/972


Re: RFR: 8290310: ChangeListener events are incorrect or misleading when a nested change occurs [v2]

2023-02-05 Thread Nir Lisker
On Tue, 3 Jan 2023 09:42:05 GMT, John Hendrikx  wrote:

>> This contains the following:
>> - Nested changes or invalidations using ExpressionHelper are delayed until 
>> the current emission completes
>>   - This fixes odd change events being produced (with incorrect oldValue)
>>   - Also fixes a bug in ExpressionHelper where a nested change would unlock 
>> the listener list early, which could cause a 
>> `ConcurrentModificationException` if a nested change was combined with a 
>> remove/add listener call
>> - A test for ExpressionHelper to verify the new behavior
>> - A test for all *Property and *Binding classes that verifies correct 
>> listener behavior at the API level (this tests gets 85% coverage on 
>> ExpressionHelper on its own, the only thing it is not testing is the locking 
>> behavior, which is not relevant at the API level).
>> - A fix for `WebColorFieldSkin` which triggered a nested change which used a 
>> flag to prevent an event loop (I've changed it now to match how 
>> `DoubleFieldSkin` and `IntegerFieldSkin` do it
>
> John Hendrikx has updated the pull request with a new target base due to a 
> merge or a rebase. The pull request now contains two commits:
> 
>  - Merge branch 'master' of https://git.openjdk.org/jfx into 
> feature/delayed-nested-emission
>  - Delay nested event emission

modules/javafx.base/src/test/java/test/javafx/beans/ObservableValueTest.java 
line 1:

> 1: package test.javafx.beans;

You will need to add a license header for a new file.

-

PR: https://git.openjdk.org/jfx/pull/837


Re: RFR: 8290310: ChangeListener events are incorrect or misleading when a nested change occurs [v2]

2023-02-05 Thread Nir Lisker
On Tue, 3 Jan 2023 09:42:05 GMT, John Hendrikx  wrote:

>> This contains the following:
>> - Nested changes or invalidations using ExpressionHelper are delayed until 
>> the current emission completes
>>   - This fixes odd change events being produced (with incorrect oldValue)
>>   - Also fixes a bug in ExpressionHelper where a nested change would unlock 
>> the listener list early, which could cause a 
>> `ConcurrentModificationException` if a nested change was combined with a 
>> remove/add listener call
>> - A test for ExpressionHelper to verify the new behavior
>> - A test for all *Property and *Binding classes that verifies correct 
>> listener behavior at the API level (this tests gets 85% coverage on 
>> ExpressionHelper on its own, the only thing it is not testing is the locking 
>> behavior, which is not relevant at the API level).
>> - A fix for `WebColorFieldSkin` which triggered a nested change which used a 
>> flag to prevent an event loop (I've changed it now to match how 
>> `DoubleFieldSkin` and `IntegerFieldSkin` do it
>
> John Hendrikx has updated the pull request with a new target base due to a 
> merge or a rebase. The pull request now contains two commits:
> 
>  - Merge branch 'master' of https://git.openjdk.org/jfx into 
> feature/delayed-nested-emission
>  - Delay nested event emission

The fix for the bug with nested events releasing the lock seems fine. I'm still 
not sure if the behavioral change is what we want the result to be even if it's 
better than what we have now. I have mentioned this in 
https://github.com/openjdk/jfx/pull/108#issuecomment-590878643. we need to 
decide on a spec first, and there are several facets to it as discussed in the 
mailing list link above 
(https://github.com/openjdk/jfx/pull/837#pullrequestreview-1233910264).

I will re-summarize what I think needs to be defined before implementing a 
behavior change like the one proposed here:

### Listener order

When listeners are registered, they are added to some collection (an array, 
currently). The add/remove methods hint at an order, but don't guarantee one. 
Do we specify an order, or say it's unspecified?

### Event dispatch order

The order in which listeners are triggered is not necessarily the order of the 
listeners above. Do we specify a dispatch order, or say it's unspecified? If 
it's specified, the listener order is probably also specified.

We are also dispatching invalidation events before change events arbitrarily. 
Do we dispatch the event to all listeners of one type and then to the other, or 
do we want to combine them according to a joint dispatch order? We either say 
that they are dispatched separately, together in some order (like 
registration), or that it's unspecified.

### Nested listener modifications

If a listener is added/removed during an event dispatch, do we specify it will 
affect ("be in time for") the nested event chain, the outer event chain, or 
that it's unspecified?

### Nested value modifications

If a listener changes the value of its property during an event dispatch, do we 
specify that the new event will trigger first, halting the current event 
dispatch (depth-first approach), or that the new event waits until current one 
finishes (breadth-first approach), or that it is unspecified? Do we guarantee 
that when a listener is invoked it sees the new value that was set by the 
latest nested change, or will it see the value that existed at trigger time, or 
is it unspecified?

If listeners affect each other with nested events, then the dispatch order 
matters.

---

If we answer "unspecified" to the questions above, it allows us more 
implementation freedom. It will also mean that listeners should be thought of 
as "lone wolves" - they are not intended to talk to each other or depend on 
each other; each should do something regardless of what the others are doing 
and assume its code "territory" is not affected by other listeners. The user 
takes responsibility for coupling them (nested modifications).
On the other hand, no guarantees bring limited usage. The question is, what is 
the intended usage?

-

PR: https://git.openjdk.org/jfx/pull/837


Re: RFR: 8173321: TableView: Click on right trough has no effect when cell height is higher than viewport height [v5]

2023-02-05 Thread JoachimSchriek
> This is my (joachim.schr...@gmx.de) first contribution to openjfx. My 
> Contributor Agreement is signed but still in review.
> So please be patient with an absolute beginner as contributor ... .
> The work of this pull request was fully done in my spare time.
> 
> I first filed the bug myself in 2017. I had begun working with JavaFX in 2014.
> 
> The two changes address the two problems mentioned in JDK-8173321:
> - Using a JavaFX TableView, a click on the right trough has no effect when 
> the cell height of the cell currently displayed is higher than viewport height
> - The ScrollBar ist displayed with a minimal height.
> 
> The changes were tested and ran well with Java 17 and the current master 
> branch of openjfx.

JoachimSchriek has updated the pull request incrementally with one additional 
commit since the last revision:

  Delete VirtualFlow.java
  
  Revert unintentional changes to VirtualFlow

-

Changes:
  - all: https://git.openjdk.org/jfx/pull/985/files
  - new: https://git.openjdk.org/jfx/pull/985/files/c35424d3..e7e9bc99

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jfx&pr=985&range=04
 - incr: https://webrevs.openjdk.org/?repo=jfx&pr=985&range=03-04

  Stats: 3392 lines in 1 file changed: 0 ins; 3392 del; 0 mod
  Patch: https://git.openjdk.org/jfx/pull/985.diff
  Fetch: git fetch https://git.openjdk.org/jfx pull/985/head:pull/985

PR: https://git.openjdk.org/jfx/pull/985


Re: RFR: 8173321: TableView: Click on right trough has no effect when cell height is higher than viewport height [v4]

2023-02-05 Thread JoachimSchriek
> This is my (joachim.schr...@gmx.de) first contribution to openjfx. My 
> Contributor Agreement is signed but still in review.
> So please be patient with an absolute beginner as contributor ... .
> The work of this pull request was fully done in my spare time.
> 
> I first filed the bug myself in 2017. I had begun working with JavaFX in 2014.
> 
> The two changes address the two problems mentioned in JDK-8173321:
> - Using a JavaFX TableView, a click on the right trough has no effect when 
> the cell height of the cell currently displayed is higher than viewport height
> - The ScrollBar ist displayed with a minimal height.
> 
> The changes were tested and ran well with Java 17 and the current master 
> branch of openjfx.

JoachimSchriek has updated the pull request incrementally with one additional 
commit since the last revision:

  Changes made following findings from review

-

Changes:
  - all: https://git.openjdk.org/jfx/pull/985/files
  - new: https://git.openjdk.org/jfx/pull/985/files/7ad99bde..c35424d3

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jfx&pr=985&range=03
 - incr: https://webrevs.openjdk.org/?repo=jfx&pr=985&range=02-03

  Stats: 83 lines in 3 files changed: 39 ins; 23 del; 21 mod
  Patch: https://git.openjdk.org/jfx/pull/985.diff
  Fetch: git fetch https://git.openjdk.org/jfx pull/985/head:pull/985

PR: https://git.openjdk.org/jfx/pull/985


Re: RFR: 8173321: TableView: Click on right trough has no effect when cell height is higher than viewport height [v3]

2023-02-05 Thread JoachimSchriek
On Sat, 4 Feb 2023 15:27:13 GMT, Kevin Rushforth  wrote:

>> JoachimSchriek has updated the pull request incrementally with one 
>> additional commit since the last revision:
>> 
>>   Deleted trailing whitespace
>
> modules/javafx.controls/src/main/java/javafx/scene/control/skin/VirtualFlow.java
>  line 2611:
> 
>> 2609: 
>> 2610: lengthBar.setMax(1);
>> 2611: lengthBar.setVisibleAmount( numCellsVisibleOnScreen / 
>> (float) cellCount);
> 
> I'm concerned with the change to no longer use the estimated size. This will 
> produce very different results for tables with variable row hights. @johanvos 
> will very likely want to comment on this.
> 
> Also, The cast is unnecessary.
> 
> Minor: remove the space after the `(`

I am very sorry at this point. I have made a mistake here because my changes 
were based on the code I had seen in 2017 and reported in JDK-8173321. At that 
time, the size calculation of the ScrollBar was based on the integer value of 
numCellsVisibleOnScreen.
I will revert the changes to VirtualFlow.

-

PR: https://git.openjdk.org/jfx/pull/985


Re: RFR: 8173321: TableView: Click on right trough has no effect when cell height is higher than viewport height [v3]

2023-02-05 Thread JoachimSchriek
On Sat, 4 Feb 2023 15:16:28 GMT, Kevin Rushforth  wrote:

>> JoachimSchriek has updated the pull request incrementally with one 
>> additional commit since the last revision:
>> 
>>   Deleted trailing whitespace
>
> modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/VirtualScrollBar.java
>  line 135:
> 
>> 133: /**
>> 134:  * JDK-8173321: Click on trough has no effect when cell 
>> height > viewport height:
>> 135:  * Solution: Scroll one cell further up resp. down if only 
>> one cell is shown.
> 
> We generally do not refer to specific bug IDs in source code comments. 
> Rather, describe the purpose of this block. Also, please spell out `resp.` -- 
> I can't figure out what it is supposed to mean.

I will change the comment in my next commit to:
Scroll one cell further in the direction the user has clicked if only one cell 
is shown.
Otherwise, a click on the trough would have no effect when cell height > 
viewport height.

> modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/VirtualScrollBar.java
>  line 151:
> 
>> 149: IndexedCell cell = firstVisibleCell;
>> 150: if (cell == null)
>> 151: return;
> 
> Unless the if statement, including its target, is entirely on one line, you 
> _must_ enclose the target of the `if` with curly braces, like this:
> 
> 
> if (cell == null) {
> return;
> }
> 
> 
> Since it fits on one line, the prior code is also acceptable:
> 
> 
> if (cell == null) return;

I will change this to the first alternative in my next commit.

> modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/VirtualScrollBar.java
>  line 156:
> 
>> 154: IndexedCell cell = lastVisibleCell;
>> 155: if (cell == null)
>> 156: return;
> 
> Either revert this or enclose in curly braces.

I will change this to the first alternative in my next commit.

-

PR: https://git.openjdk.org/jfx/pull/985


Re: Feedback requested for infrastructure for properties that wish to delay registering listeners

2023-02-05 Thread John Hendrikx

Any comments on this?

I think having API to make it easier for both JavaFX and users to create 
listeners that can delay registration to their own dependencies. This 
would be an alternative to using weak listeners for these cases.


--John

On 19/01/2023 16:49, John Hendrikx wrote:

Hi list,

I've been looking into what it would take to make the design of 
properties which only register listeners when needed easier to 
implement with JavaFX, both for JavaFX itself as well as for the 
user.  This is the result of my investigation into ListProperty (and 
other collection properties) and how hard it would be to change their 
semantics to only register listeners when they're absolutely required 
for the correct functioning of the class.


Currently, JavaFX doesn't offer the tools one would need to register 
listeners in a just-in-time fashion.  This is because there is no 
notification mechanism available in its observable values when they 
become observed or unobserved. The closest thing there currently 
exists is what ObjectBinding and LazyObjectBinding offer:


From ObjectBinding:

    /**
 * Checks if the binding has at least one listener registered on 
it. This
 * is useful for subclasses which want to conserve resources when 
not observed.

 *
 * @return {@code true} if this binding currently has one or more
 * listeners registered on it, otherwise {@code false}
 * @since 19
 */
    protected final boolean isObserved() {
    return helper != null;
    }

From LazyObjectBinding:

    /**
 * Called after a listener was added to start observing inputs if 
they're not observed already.

 */
    private void updateSubscriptionAfterAdd() { ... }

    /**
 * Called after a listener was removed to stop observing inputs if 
this was the last listener

 * observing this binding.
 */
    private void updateSubscriptionAfterRemove() { ... }

I'm proposing to extend the JavaFX with new methods that can be used 
to stay informed about the observable's current observed status. These 
methods will facilitate implementations of properties that wish to 
delay registering listeners until they are themselves observed. This 
can save memory, save unnecessary notifications via events and reduces 
the need for weak listener constructs.


The proposal does not require any new fields, and would default to 
reporting observable values as being observed. Most JavaFX observable 
values should be retrofitted to support this functionality -- the ones 
relying on a form of ExpressionHelper will only require minimal 
changes with minimal impact.


The methods that I would like to see added are the following:

In ObservableValue:

    /**
 * Checks if this ObservableValue is currently observed. If 
unknown or unsupported,

 * {@code true} is returned.
 *
 * @return {@code true} if this ObservableValue currently has one 
or more

 * listeners registered on it, otherwise {@code false}
 */
    default boolean isObserved() { return true; }

The above method is useful for debugging, but its primary use is for 
complex properties which observed status is determined by not only its 
direct listeners but also any child properties it may offer.  
ListProperty is such an example, which offers child properties size 
and empty. Its observed status would be determined like this:


 helper != null || (size0 != null && size0.isObserved()) || 
(empty0 != null && empty0.isObserved())


Further, we need two protected callback methods.  These should be 
added in all Binding and Property Base classes (basically all classes 
that implement addListener/removeListener methods). These are called 
when the observed status of the property changes:


    /**
 * Called when this property transitions from unobserved to observed.
 */
    protected void observed() {}

    /**
 * Called when this property transitions from observed to unobserved.
 */
    protected void unobserved() {}

These methods are implemented by child properties in order to inform 
the parent that their observed status has changed, which may require 
the parent property to change its status as well.


When implemented, LazyObjectBinding can be simplified as some or all 
of its functionality will be part of ObjectBinding (LazyObjectBinding 
is not a public class at the moment).  The isObserved method in 
ObjectBinding would go from protected to public (it's already final).


Implementation for classes that rely on a form of ExpressionHelper is 
simple; they can check if the helper is null or not (for isObserved) 
and check if the nullity changed during addListener/removeListener 
calls to make their call to "observed" or "unobserved".  No additional 
fields are required.


I've added a proof of concept here 
(https://github.com/openjdk/jfx/pull/1004) where `ListPropertyBase` 
was altered to use these new methods to delay its listener 
registration and to remove its listener when no longer obs

Re: RFR: JDK-8298528: Clean up raw type warnings in base in bindings and collections packages [v2]

2023-02-05 Thread John Hendrikx
On Wed, 4 Jan 2023 05:28:10 GMT, Nir Lisker  wrote:

>> John Hendrikx has updated the pull request incrementally with two additional 
>> commits since the last revision:
>> 
>>  - Clean up expression classes repeated null checks
>>  - Use instanceof with pattern matching in a few spots
>
> I took a closer look at the sorting-related classes. I think that the design 
> there is not ideal. Fixing it might be out of scope for this PR. I wouldn't 
> mind fixing it myself, by the way.
> 
> The way the JDK treats soring on lists is with a single `sort(Comparable c)` 
> method that, when receiving `null`, assumes that the elements are 
> `Comparable` and throws if not. `Collections` has 2 static sorting methods 
> that help enforce this condition, where the one that doesn't take a 
> `Comparator` passes `null` to the one that does.
> 
> JavaFX tries to emulate this. `FXCollections` has the same 2 methods for 
> `ObservableList`, but one doesn't call the other. The asymmetry comes from 
> `SortableList` (which doesn't live up to its name - non-sortable lists can 
> also implement it). It defines a 0-argument method and a 
> `Comparator`-argument method as different behaviors, instead of one calling 
> the other. This is deferred to its implementations, `ObservableListWrapper` 
> and `ObservableSequentialListWrapper`, which make the differentiation by, 
> again, calling 2 different methods on `SortHelper`.
> 
> I suggest that the argument check be made at the lowest level, like in the 
> JDK (inside `Arrays` sort method). First, `FXCollections` can change to:
> 
> 
> public static > void 
> sort(ObservableList list) {
> sort(list, null); // or Comparator.naturalOrder() instead of null
> }
> 
> public static  void sort(ObservableList list, Comparator 
> c) {
> if (list instanceof SortableList) {
> list.sort(c);
> } else {
> List newContent = new ArrayList<>(list);
> newContent.sort(c);
> list.setAll(newContent);
> }
> }
> 
> 
> `SortableList` then removes its `sort()` method, and now it's just overriding 
> `List::sort(Comparator)` without doing anything with it, so it can be removed 
> too, and it's left as a marker interface for the special sorting in 
> `SortHelper` (I haven't understood yet why it's better , I need to dig there 
> more):
> 
> 
> public interface SortableList {}
> 
> 
> Now `ObservableListWrapper` and `ObservableSequentialListWrapper` also remove 
> `sort()`, and override `List::sort(Comparator)` directly and in accordance 
> with its contract, passing the (possibly `null`) comparator to `SortHelper`, 
> which is akin to the JDK's `Arrays::sort` method.
> 
> Now I need to look into `SortHelper` to see what it does exactly and how to 
> change it. I think it doesn't need the `sort(List list)` method too now 
> because it doesn't really enforce that the elements are `Comparable`, it will 
> naturally throw if not.
> 
> ---
> 
> In my opinion, this is the design flaw: `ObservableList` should have 
> overridden `List`'s sort method to specify that its sorting is done as one 
> change:
> 
> 
> public interface ObservableList extends List, Observable {
> 
> @Override
> default void sort(Comparator c) {
> var newContent = new ArrayList<>(this);
> newContent.sort(c);
> setAll(newContent);
> }
> 
> 
> Then we wouldn't need the `SortableList` marker because `FXCollections` could 
> just call this method directly (like `Collections` does, which means that 
> `FXCollections`'s methods are not needed anymore, though we can't remove 
> them), and whichever implementation wants to do a more efficient sorting, 
> like `ObservableListWrapper`, can override again.
> This will be a behavioral change, though, because the generated change events 
> differ.

@nlisker I think I made all modifications requested, is there anything else 
that should be done here? Do you want the sort changes to be made or an issue 
be filed for it?

-

PR: https://git.openjdk.org/jfx/pull/972


Re: RFR: 8290310: ChangeListener events are incorrect or misleading when a nested change occurs [v2]

2023-02-05 Thread John Hendrikx
On Tue, 3 Jan 2023 09:42:05 GMT, John Hendrikx  wrote:

>> This contains the following:
>> - Nested changes or invalidations using ExpressionHelper are delayed until 
>> the current emission completes
>>   - This fixes odd change events being produced (with incorrect oldValue)
>>   - Also fixes a bug in ExpressionHelper where a nested change would unlock 
>> the listener list early, which could cause a 
>> `ConcurrentModificationException` if a nested change was combined with a 
>> remove/add listener call
>> - A test for ExpressionHelper to verify the new behavior
>> - A test for all *Property and *Binding classes that verifies correct 
>> listener behavior at the API level (this tests gets 85% coverage on 
>> ExpressionHelper on its own, the only thing it is not testing is the locking 
>> behavior, which is not relevant at the API level).
>> - A fix for `WebColorFieldSkin` which triggered a nested change which used a 
>> flag to prevent an event loop (I've changed it now to match how 
>> `DoubleFieldSkin` and `IntegerFieldSkin` do it
>
> John Hendrikx has updated the pull request with a new target base due to a 
> merge or a rebase. The pull request now contains two commits:
> 
>  - Merge branch 'master' of https://git.openjdk.org/jfx into 
> feature/delayed-nested-emission
>  - Delay nested event emission

@arapte @nlisker what do you think?

-

PR: https://git.openjdk.org/jfx/pull/837


Re: RFR: 8290765: Remove parent disabled/treeVisible listeners [v5]

2023-02-05 Thread John Hendrikx
On Fri, 3 Feb 2023 23:31:24 GMT, Michael Strauß  wrote:

>> `Node` adds InvalidationListeners to its parent's `disabled` and 
>> `treeVisible` properties and calls its own `updateDisabled()` and 
>> `updateTreeVisible(boolean)` methods when the property values change.
>> 
>> These listeners are not required, since `Node` can easily call the 
>> `updateDisabled()` and `updateTreeVisible(boolean)` methods on its children, 
>> saving the memory cost of maintaining listeners and bindings.
>
> Michael Strauß has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   improved tests, changed foreach loop

Marked as reviewed by jhendrikx (Committer).

-

PR: https://git.openjdk.org/jfx/pull/841