Re: [ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`

2013-12-16 Thread Tomas Mikula
Never mind,

b.bind(a);

should not be equivalent to

a.addListener(o - b.set(a.get()));

in the first place, but rather to

a.addListener(o - b.set(a.get()));
b.set(a.get()); // don't forget this!

When I fixed my example, I'm not observing any difference in behavior.
I'm still not getting the behavior I want, but due to
https://javafx-jira.kenai.com/browse/RT-34897.

Thanks,
Tomas

On Mon, Dec 16, 2013 at 8:37 PM, Anthony Petrov
anthony.pet...@oracle.com wrote:
 Filing a bug never hurts. We'll either fix it, or close it and explain why
 it's not a bug then.

 --
 best regards,
 Anthony


 On 12/13/2013 11:17 PM, Tomas Mikula wrote:

 I guess my main question is: should I file a bug on ListView?

 Tomas

 On Fri, Dec 13, 2013 at 8:15 PM, Tomas Mikula tomas.mik...@gmail.com
 wrote:

 I just came across a strange case when these two are not equivalent.
 Maybe that is no surprise to you, but it was to me. The case I
 stumbled upon most likely has to do with ListView internals.

 Substitute
 a := ListView.widthProperty()
 b := ListCell.prefWidthProperty()

 and the code that demonstrates the difference:


 public class Test extends Application {

  private static class MyCell extends ListCellString {
  public MyCell(ListViewString lv) {
  setMaxWidth(Region.USE_PREF_SIZE);

  // !!! comment out exactly one of the following
  // !!! two lines to demonstrate the difference
  prefWidthProperty().bind(lv.widthProperty());
  lv.widthProperty().addListener(o -
 setPrefWidth(lv.getWidth()));
  }

  @Override
  protected void updateItem(String item, boolean empty) {
  super.updateItem(item, empty);
  setGraphic(empty ? null : new TextFlow(new Text(item)));
  }
  }

  @Override
  public void start(Stage stage) {
  ListViewString listView = new ListView();
  listView.setCellFactory(lv - new MyCell(lv));
  listView.getItems().add(This is a very long line that needs
 to be wrapped);

  StackPane stack = new StackPane();
  stack.getChildren().add(listView);
  Scene scene = new Scene(stack, 200, 100);
  stage.setScene(scene);
  stage.show();
  }

  public static void main(String[] args) {
  launch(args);
  }
 }


 When I run the bind version, the text shows up wrapped.
 When I run the addListener version, the text shows up in one long line.

 Do you think this is a bug in ListView, or is there a reasonable
 explanation?

 Just for the record, I consider the wrapping behavior to be the correct
 one.


 My *speculation* about the possible cause follows:

 The only case I could come up with when
 A) b.bind(a)
 and
 B) a.addListener(o - b.set(a.get()))
 are effectively different is when both of these conditions hold:
 1) there is an invalidation listener set on b that causes b to become
 valid (e.g. calls b.get()); and
 2) a is invalidated twice in a row, but recomputes to the same value each
 time.

 Now the scenarios for A) and B) differ:

 Scenario A (b.bind(a)):
   - a is invalidated for the first time
   - b's invalidation listener is called for the first time
   - b is now valid
   - a is invalidated for the second time
   - b's invalidation listener is called for the *SECOND* time

 Scenario B (a.addListener(o - b.set(a.get(:
   - a is invalidated for the first time
   - b is set to a.get() = x and b's invalidation listener is called for
 the first time
   - b is now valid
   - a is invalidated for the second time
   - b is set to a.get() = x and b's invalidation listener is *NOT*
 called for the second time, because b's value did not change

 In scenario A, b's invalidation listener is called twice, while in
 scenario B just once. If weird things are happening in this
 invalidation listener, this can result in different behavior.

 Now, if b is ListCell.prefWidthProperty(), scenario A and scenario B
 cause it to be invalidated different number of times, which, my
 *speculation*, could yield different behavior.
 This is how far I got.

 Cheers,
 Tomas


[ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`

2013-12-13 Thread Tomas Mikula
I just came across a strange case when these two are not equivalent.
Maybe that is no surprise to you, but it was to me. The case I
stumbled upon most likely has to do with ListView internals.

Substitute
a := ListView.widthProperty()
b := ListCell.prefWidthProperty()

and the code that demonstrates the difference:


public class Test extends Application {

private static class MyCell extends ListCellString {
public MyCell(ListViewString lv) {
setMaxWidth(Region.USE_PREF_SIZE);

// !!! comment out exactly one of the following
// !!! two lines to demonstrate the difference
prefWidthProperty().bind(lv.widthProperty());
lv.widthProperty().addListener(o - setPrefWidth(lv.getWidth()));
}

@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setGraphic(empty ? null : new TextFlow(new Text(item)));
}
}

@Override
public void start(Stage stage) {
ListViewString listView = new ListView();
listView.setCellFactory(lv - new MyCell(lv));
listView.getItems().add(This is a very long line that needs
to be wrapped);

StackPane stack = new StackPane();
stack.getChildren().add(listView);
Scene scene = new Scene(stack, 200, 100);
stage.setScene(scene);
stage.show();
}

public static void main(String[] args) {
launch(args);
}
}


When I run the bind version, the text shows up wrapped.
When I run the addListener version, the text shows up in one long line.

Do you think this is a bug in ListView, or is there a reasonable explanation?

Just for the record, I consider the wrapping behavior to be the correct one.


My *speculation* about the possible cause follows:

The only case I could come up with when
A) b.bind(a)
and
B) a.addListener(o - b.set(a.get()))
are effectively different is when both of these conditions hold:
1) there is an invalidation listener set on b that causes b to become
valid (e.g. calls b.get()); and
2) a is invalidated twice in a row, but recomputes to the same value each time.

Now the scenarios for A) and B) differ:

Scenario A (b.bind(a)):
 - a is invalidated for the first time
 - b's invalidation listener is called for the first time
 - b is now valid
 - a is invalidated for the second time
 - b's invalidation listener is called for the *SECOND* time

Scenario B (a.addListener(o - b.set(a.get(:
 - a is invalidated for the first time
 - b is set to a.get() = x and b's invalidation listener is called for
the first time
 - b is now valid
 - a is invalidated for the second time
 - b is set to a.get() = x and b's invalidation listener is *NOT*
called for the second time, because b's value did not change

In scenario A, b's invalidation listener is called twice, while in
scenario B just once. If weird things are happening in this
invalidation listener, this can result in different behavior.

Now, if b is ListCell.prefWidthProperty(), scenario A and scenario B
cause it to be invalidated different number of times, which, my
*speculation*, could yield different behavior.
This is how far I got.

Cheers,
Tomas


Re: [ListView] `b.bind(a)` not behaviorally equivalent to `a.addListener(o - b.set(a.get()))`

2013-12-13 Thread Tomas Mikula
I guess my main question is: should I file a bug on ListView?

Tomas

On Fri, Dec 13, 2013 at 8:15 PM, Tomas Mikula tomas.mik...@gmail.com wrote:
 I just came across a strange case when these two are not equivalent.
 Maybe that is no surprise to you, but it was to me. The case I
 stumbled upon most likely has to do with ListView internals.

 Substitute
 a := ListView.widthProperty()
 b := ListCell.prefWidthProperty()

 and the code that demonstrates the difference:


 public class Test extends Application {

 private static class MyCell extends ListCellString {
 public MyCell(ListViewString lv) {
 setMaxWidth(Region.USE_PREF_SIZE);

 // !!! comment out exactly one of the following
 // !!! two lines to demonstrate the difference
 prefWidthProperty().bind(lv.widthProperty());
 lv.widthProperty().addListener(o - setPrefWidth(lv.getWidth()));
 }

 @Override
 protected void updateItem(String item, boolean empty) {
 super.updateItem(item, empty);
 setGraphic(empty ? null : new TextFlow(new Text(item)));
 }
 }

 @Override
 public void start(Stage stage) {
 ListViewString listView = new ListView();
 listView.setCellFactory(lv - new MyCell(lv));
 listView.getItems().add(This is a very long line that needs
 to be wrapped);

 StackPane stack = new StackPane();
 stack.getChildren().add(listView);
 Scene scene = new Scene(stack, 200, 100);
 stage.setScene(scene);
 stage.show();
 }

 public static void main(String[] args) {
 launch(args);
 }
 }


 When I run the bind version, the text shows up wrapped.
 When I run the addListener version, the text shows up in one long line.

 Do you think this is a bug in ListView, or is there a reasonable explanation?

 Just for the record, I consider the wrapping behavior to be the correct one.


 My *speculation* about the possible cause follows:

 The only case I could come up with when
 A) b.bind(a)
 and
 B) a.addListener(o - b.set(a.get()))
 are effectively different is when both of these conditions hold:
 1) there is an invalidation listener set on b that causes b to become
 valid (e.g. calls b.get()); and
 2) a is invalidated twice in a row, but recomputes to the same value each 
 time.

 Now the scenarios for A) and B) differ:

 Scenario A (b.bind(a)):
  - a is invalidated for the first time
  - b's invalidation listener is called for the first time
  - b is now valid
  - a is invalidated for the second time
  - b's invalidation listener is called for the *SECOND* time

 Scenario B (a.addListener(o - b.set(a.get(:
  - a is invalidated for the first time
  - b is set to a.get() = x and b's invalidation listener is called for
 the first time
  - b is now valid
  - a is invalidated for the second time
  - b is set to a.get() = x and b's invalidation listener is *NOT*
 called for the second time, because b's value did not change

 In scenario A, b's invalidation listener is called twice, while in
 scenario B just once. If weird things are happening in this
 invalidation listener, this can result in different behavior.

 Now, if b is ListCell.prefWidthProperty(), scenario A and scenario B
 cause it to be invalidated different number of times, which, my
 *speculation*, could yield different behavior.
 This is how far I got.

 Cheers,
 Tomas