Skip to content

Commit fc770fb

Browse files
author
Andy Goryachev
committed
8349091: Charts: exception initializing in a background thread
Reviewed-by: kizune, kcr
1 parent 1824db5 commit fc770fb

File tree

11 files changed

+215
-140
lines changed

11 files changed

+215
-140
lines changed

Diff for: modules/javafx.controls/src/main/java/javafx/scene/chart/AreaChart.java

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,24 +25,33 @@
2525

2626
package javafx.scene.chart;
2727

28-
import java.util.*;
29-
28+
import java.util.ArrayList;
29+
import java.util.Collections;
30+
import java.util.HashMap;
31+
import java.util.Iterator;
32+
import java.util.List;
33+
import java.util.Map;
3034
import javafx.animation.FadeTransition;
3135
import javafx.animation.Interpolator;
3236
import javafx.animation.KeyFrame;
3337
import javafx.animation.KeyValue;
3438
import javafx.animation.Timeline;
35-
import javafx.application.Platform;
3639
import javafx.beans.NamedArg;
3740
import javafx.beans.property.BooleanProperty;
3841
import javafx.beans.property.DoubleProperty;
3942
import javafx.beans.property.SimpleDoubleProperty;
4043
import javafx.collections.FXCollections;
4144
import javafx.collections.ListChangeListener;
4245
import javafx.collections.ObservableList;
46+
import javafx.css.CssMetaData;
47+
import javafx.css.Styleable;
48+
import javafx.css.StyleableBooleanProperty;
49+
import javafx.css.StyleableProperty;
50+
import javafx.css.converter.BooleanConverter;
4351
import javafx.scene.AccessibleRole;
4452
import javafx.scene.Group;
4553
import javafx.scene.Node;
54+
import javafx.scene.chart.LineChart.SortingPolicy;
4655
import javafx.scene.layout.StackPane;
4756
import javafx.scene.shape.ClosePath;
4857
import javafx.scene.shape.LineTo;
@@ -51,14 +60,7 @@
5160
import javafx.scene.shape.PathElement;
5261
import javafx.scene.shape.StrokeLineJoin;
5362
import javafx.util.Duration;
54-
5563
import com.sun.javafx.charts.Legend.LegendItem;
56-
import javafx.css.converter.BooleanConverter;
57-
import javafx.css.CssMetaData;
58-
import javafx.css.Styleable;
59-
import javafx.css.StyleableBooleanProperty;
60-
import javafx.css.StyleableProperty;
61-
import javafx.scene.chart.LineChart.SortingPolicy;
6264

6365
/**
6466
* AreaChart - Plots the area between the line that connects the data points and
@@ -541,7 +543,7 @@ private Node createSymbol(Series<X,Y> series, int seriesIndex, final Data<X,Y> i
541543
symbol = new StackPane();
542544
symbol.setAccessibleRole(AccessibleRole.TEXT);
543545
symbol.setAccessibleRoleDescription("Point");
544-
symbol.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
546+
symbol.setFocusTraversable(isAccessibilityActive());
545547
item.setNode(symbol);
546548
}
547549
// set symbol styles

Diff for: modules/javafx.controls/src/main/java/javafx/scene/chart/BarChart.java

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,38 +25,38 @@
2525

2626
package javafx.scene.chart;
2727

28-
import java.util.*;
29-
30-
import javafx.scene.AccessibleRole;
28+
import java.util.ArrayList;
29+
import java.util.Collections;
30+
import java.util.HashMap;
31+
import java.util.HashSet;
32+
import java.util.Iterator;
33+
import java.util.List;
34+
import java.util.Map;
3135
import javafx.animation.Animation;
3236
import javafx.animation.FadeTransition;
3337
import javafx.animation.Interpolator;
3438
import javafx.animation.KeyFrame;
3539
import javafx.animation.KeyValue;
3640
import javafx.animation.ParallelTransition;
3741
import javafx.animation.Timeline;
38-
import javafx.application.Platform;
3942
import javafx.beans.NamedArg;
4043
import javafx.beans.property.DoubleProperty;
4144
import javafx.collections.FXCollections;
45+
import javafx.collections.ListChangeListener;
4246
import javafx.collections.ObservableList;
47+
import javafx.css.CssMetaData;
48+
import javafx.css.PseudoClass;
49+
import javafx.css.Styleable;
50+
import javafx.css.StyleableDoubleProperty;
51+
import javafx.css.StyleableProperty;
52+
import javafx.css.converter.SizeConverter;
4353
import javafx.geometry.Orientation;
54+
import javafx.scene.AccessibleRole;
4455
import javafx.scene.Node;
4556
import javafx.scene.layout.StackPane;
4657
import javafx.util.Duration;
47-
4858
import com.sun.javafx.charts.Legend.LegendItem;
4959

50-
import javafx.css.StyleableDoubleProperty;
51-
import javafx.css.CssMetaData;
52-
import javafx.css.PseudoClass;
53-
54-
import javafx.css.converter.SizeConverter;
55-
import javafx.collections.ListChangeListener;
56-
57-
import javafx.css.Styleable;
58-
import javafx.css.StyleableProperty;
59-
6060
/**
6161
* A chart that plots bars indicating data values for a category. The bars can be vertical or horizontal depending on
6262
* which axis is a category axis.
@@ -559,7 +559,7 @@ private Node createBar(Series<X,Y> series, int seriesIndex, final Data<X,Y> item
559559
bar = new StackPane();
560560
bar.setAccessibleRole(AccessibleRole.TEXT);
561561
bar.setAccessibleRoleDescription("Bar");
562-
bar.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
562+
bar.setFocusTraversable(isAccessibilityActive());
563563
item.setNode(bar);
564564
}
565565
bar.getStyleClass().setAll("chart-bar", "series" + seriesIndex, "data" + itemIndex, series.defaultColorStyleClass);

Diff for: modules/javafx.controls/src/main/java/javafx/scene/chart/BubbleChart.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,8 @@
2828
import java.util.ArrayList;
2929
import java.util.Iterator;
3030
import java.util.List;
31-
3231
import javafx.animation.FadeTransition;
3332
import javafx.animation.ParallelTransition;
34-
import javafx.application.Platform;
3533
import javafx.beans.NamedArg;
3634
import javafx.collections.FXCollections;
3735
import javafx.collections.ObservableList;
@@ -41,7 +39,6 @@
4139
import javafx.scene.layout.StackPane;
4240
import javafx.scene.shape.Ellipse;
4341
import javafx.util.Duration;
44-
4542
import com.sun.javafx.charts.Legend.LegendItem;
4643

4744
/**
@@ -270,7 +267,7 @@ public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object...
270267
};
271268
bubble.setAccessibleRole(AccessibleRole.TEXT);
272269
bubble.setAccessibleRoleDescription("Bubble");
273-
bubble.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
270+
bubble.setFocusTraversable(isAccessibilityActive());
274271
item.setNode(bubble);
275272
}
276273
// set bubble styles

Diff for: modules/javafx.controls/src/main/java/javafx/scene/chart/Chart.java

+74-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,9 +28,6 @@
2828
import java.util.ArrayList;
2929
import java.util.Collections;
3030
import java.util.List;
31-
32-
import com.sun.javafx.scene.control.skin.Utils;
33-
3431
import javafx.animation.Animation;
3532
import javafx.animation.KeyFrame;
3633
import javafx.application.Platform;
@@ -40,28 +37,30 @@
4037
import javafx.beans.property.SimpleBooleanProperty;
4138
import javafx.beans.property.StringProperty;
4239
import javafx.beans.property.StringPropertyBase;
40+
import javafx.beans.value.ChangeListener;
41+
import javafx.beans.value.ObservableValue;
4342
import javafx.beans.value.WritableValue;
4443
import javafx.collections.ObservableList;
44+
import javafx.css.CssMetaData;
45+
import javafx.css.Styleable;
46+
import javafx.css.StyleableBooleanProperty;
47+
import javafx.css.StyleableObjectProperty;
48+
import javafx.css.StyleableProperty;
49+
import javafx.css.converter.BooleanConverter;
50+
import javafx.css.converter.EnumConverter;
4551
import javafx.geometry.Pos;
4652
import javafx.geometry.Side;
4753
import javafx.scene.Node;
54+
import javafx.scene.Scene;
4855
import javafx.scene.control.Label;
4956
import javafx.scene.layout.Pane;
5057
import javafx.scene.layout.Region;
51-
58+
import javafx.stage.Window;
59+
import javafx.util.Subscription;
5260
import com.sun.javafx.charts.ChartLayoutAnimator;
5361
import com.sun.javafx.charts.Legend;
5462
import com.sun.javafx.scene.NodeHelper;
55-
56-
import javafx.css.StyleableBooleanProperty;
57-
import javafx.css.StyleableObjectProperty;
58-
import javafx.css.CssMetaData;
59-
60-
import javafx.css.converter.BooleanConverter;
61-
import javafx.css.converter.EnumConverter;
62-
63-
import javafx.css.Styleable;
64-
import javafx.css.StyleableProperty;
63+
import com.sun.javafx.scene.control.skin.Utils;
6564

6665
/**
6766
* Base class for all charts. It has 3 parts the title, legend and chartContent. The chart content is populated by the
@@ -104,6 +103,9 @@ public abstract class Chart extends Region {
104103
/** Animator for animating stuff on the chart */
105104
private final ChartLayoutAnimator animator = new ChartLayoutAnimator(chartContent);
106105

106+
// SimpleBooleanProperty or Subscription
107+
private volatile Object accessibilityActive;
108+
107109
// -------------- PUBLIC PROPERTIES --------------------------------------------------------------------------------
108110

109111
/** The chart title */
@@ -274,7 +276,6 @@ protected ObservableList<Node> getChartChildren() {
274276
*/
275277
public Chart() {
276278
titleLabel.setAlignment(Pos.CENTER);
277-
titleLabel.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
278279
getChildren().addAll(titleLabel, chartContent);
279280
getStyleClass().add("chart");
280281
titleLabel.getStyleClass().add("chart-title");
@@ -511,6 +512,62 @@ public StyleableProperty<Boolean> getStyleableProperty(Chart node) {
511512
return getClassCssMetaData();
512513
}
513514

514-
}
515+
private void handleAccessibilityActive(boolean on) {
516+
titleLabel.setFocusTraversable(on);
517+
updateSymbolFocusable(on);
518+
}
515519

520+
/**
521+
* Invoked in the FX application thread when accessibility active platform property changes.
522+
* The child classes should override this method to set focus traversable flag on every symbol, as well as
523+
* other elements that need to be focusable.
524+
* @param on whether the accessibility is active
525+
*/
526+
// package protected: custom charts must handle accessbility on their own
527+
void updateSymbolFocusable(boolean on) {
528+
}
516529

530+
/**
531+
* When called from JavaFX application thread, returns the value of the property.
532+
* When called from any other thread, returns false and sets up the machinery to
533+
* invoke {@code updateSymbolFocusable()} when needed.
534+
* The chart implementations should use this method to set focus travesable flags on the nodes
535+
* which needs to be focus traversable when accessibility is on.
536+
* @return
537+
*/
538+
// package protected: custom charts must handle accessbility on their own
539+
final boolean isAccessibilityActive() {
540+
if (Platform.isFxApplicationThread()) {
541+
if (accessibilityActive instanceof SimpleBooleanProperty p) {
542+
return p.get();
543+
} else {
544+
if (accessibilityActive instanceof Subscription sub) {
545+
sub.unsubscribe();
546+
}
547+
SimpleBooleanProperty active = new SimpleBooleanProperty();
548+
accessibilityActive = active;
549+
active.addListener((src, prev, on) -> {
550+
handleAccessibilityActive(on);
551+
});
552+
active.bind(Platform.accessibilityActiveProperty());
553+
return active.get();
554+
}
555+
} else {
556+
// chart and its data are allowed to be constructed in a background thread
557+
if (accessibilityActive == null) {
558+
// set up a subscription to be fired once the chart becomes a part of the scene graph
559+
accessibilityActive = sceneProperty()
560+
.flatMap(Scene::windowProperty)
561+
.subscribe((w) -> {
562+
if (w != null) {
563+
// will unsubscribe when appears in a window, in the fx app thread
564+
if (isAccessibilityActive()) {
565+
handleAccessibilityActive(true);
566+
}
567+
}
568+
});
569+
}
570+
return false;
571+
}
572+
}
573+
}

Diff for: modules/javafx.controls/src/main/java/javafx/scene/chart/LineChart.java

+9-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,17 +26,16 @@
2626
package javafx.scene.chart;
2727

2828
import java.util.ArrayList;
29+
import java.util.Collections;
2930
import java.util.HashMap;
3031
import java.util.List;
3132
import java.util.Map;
32-
33+
import javafx.animation.Animation;
3334
import javafx.animation.FadeTransition;
3435
import javafx.animation.Interpolator;
3536
import javafx.animation.KeyFrame;
3637
import javafx.animation.KeyValue;
3738
import javafx.animation.Timeline;
38-
import javafx.animation.Animation;
39-
import javafx.application.Platform;
4039
import javafx.beans.NamedArg;
4140
import javafx.beans.property.BooleanProperty;
4241
import javafx.beans.property.DoubleProperty;
@@ -46,26 +45,20 @@
4645
import javafx.collections.FXCollections;
4746
import javafx.collections.ListChangeListener;
4847
import javafx.collections.ObservableList;
48+
import javafx.css.CssMetaData;
49+
import javafx.css.Styleable;
50+
import javafx.css.StyleableBooleanProperty;
51+
import javafx.css.StyleableProperty;
52+
import javafx.css.converter.BooleanConverter;
4953
import javafx.scene.AccessibleRole;
5054
import javafx.scene.Node;
5155
import javafx.scene.layout.StackPane;
5256
import javafx.scene.shape.LineTo;
5357
import javafx.scene.shape.Path;
5458
import javafx.scene.shape.StrokeLineJoin;
5559
import javafx.util.Duration;
56-
5760
import com.sun.javafx.charts.Legend.LegendItem;
5861

59-
import javafx.css.StyleableBooleanProperty;
60-
import javafx.css.CssMetaData;
61-
62-
import javafx.css.converter.BooleanConverter;
63-
64-
import java.util.*;
65-
66-
import javafx.css.Styleable;
67-
import javafx.css.StyleableProperty;
68-
6962
/**
7063
* Line Chart plots a line connecting the data points in a series. The data points
7164
* themselves can be represented by symbols optionally. Line charts are usually used
@@ -530,7 +523,7 @@ private Node createSymbol(Series<X, Y> series, int seriesIndex, final Data<X,Y>
530523
symbol = new StackPane();
531524
symbol.setAccessibleRole(AccessibleRole.TEXT);
532525
symbol.setAccessibleRoleDescription("Point");
533-
symbol.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
526+
symbol.setFocusTraversable(isAccessibilityActive());
534527
item.setNode(symbol);
535528
}
536529
// set symbol styles

0 commit comments

Comments
 (0)