Skip to content

Commit 07e693b

Browse files
author
Andy Goryachev
committed
8245145: Spinner: throws IllegalArgumentException when replacing skin
Reviewed-by: aghaisas, kcr
1 parent 5b0d3b5 commit 07e693b

File tree

3 files changed

+48
-25
lines changed

3 files changed

+48
-25
lines changed

modules/javafx.controls/src/main/java/javafx/scene/control/skin/SpinnerSkin.java

+39-24
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,31 @@
2424
*/
2525
package javafx.scene.control.skin;
2626

27-
import com.sun.javafx.scene.ParentHelper;
28-
import com.sun.javafx.scene.traversal.Algorithm;
29-
import com.sun.javafx.scene.control.FakeFocusTextField;
30-
import com.sun.javafx.scene.traversal.Direction;
31-
import com.sun.javafx.scene.traversal.ParentTraversalEngine;
32-
import javafx.scene.control.Control;
33-
import javafx.scene.control.SkinBase;
34-
import com.sun.javafx.scene.control.behavior.SpinnerBehavior;
35-
import com.sun.javafx.scene.traversal.TraversalContext;
36-
import javafx.collections.ListChangeListener;
27+
import java.util.List;
28+
3729
import javafx.css.PseudoClass;
3830
import javafx.geometry.HPos;
3931
import javafx.geometry.VPos;
4032
import javafx.scene.AccessibleAction;
4133
import javafx.scene.AccessibleRole;
4234
import javafx.scene.Node;
35+
import javafx.scene.control.Control;
36+
import javafx.scene.control.SkinBase;
4337
import javafx.scene.control.Spinner;
4438
import javafx.scene.control.TextField;
4539
import javafx.scene.input.KeyCode;
4640
import javafx.scene.input.KeyEvent;
4741
import javafx.scene.layout.Region;
4842
import javafx.scene.layout.StackPane;
4943

50-
import java.util.List;
44+
import com.sun.javafx.scene.ParentHelper;
45+
import com.sun.javafx.scene.control.FakeFocusTextField;
46+
import com.sun.javafx.scene.control.ListenerHelper;
47+
import com.sun.javafx.scene.control.behavior.SpinnerBehavior;
48+
import com.sun.javafx.scene.traversal.Algorithm;
49+
import com.sun.javafx.scene.traversal.Direction;
50+
import com.sun.javafx.scene.traversal.ParentTraversalEngine;
51+
import com.sun.javafx.scene.traversal.TraversalContext;
5152

5253
/**
5354
* Default skin implementation for the {@link Spinner} control.
@@ -80,11 +81,9 @@ public class SpinnerSkin<T> extends SkinBase<Spinner<T>> {
8081
private static final int SPLIT_ARROWS_HORIZONTAL = 5;
8182

8283
private int layoutMode = 0;
83-
8484
private final SpinnerBehavior behavior;
8585

8686

87-
8887
/* *************************************************************************
8988
* *
9089
* Constructors *
@@ -103,13 +102,15 @@ public SpinnerSkin(Spinner<T> control) {
103102

104103
// install default input map for the Button control
105104
behavior = new SpinnerBehavior<>(control);
106-
// control.setInputMap(behavior.getInputMap());
107105

108106
textField = control.getEditor();
109-
getChildren().add(textField);
107+
108+
ListenerHelper lh = ListenerHelper.get(this);
110109

111110
updateStyleClass();
112-
control.getStyleClass().addListener((ListChangeListener<String>) c -> updateStyleClass());
111+
lh.addListChangeListener(control.getStyleClass(), (ch) -> {
112+
updateStyleClass();
113+
});
113114

114115
// increment / decrement arrows
115116
incrementArrow = new Region();
@@ -169,12 +170,12 @@ public void executeAccessibleAction(AccessibleAction action, Object... parameter
169170
// Fixes in the same vein as ComboBoxListViewSkin
170171

171172
// move fake focus in to the textfield if the spinner is editable
172-
control.focusedProperty().addListener((ov, t, hasFocus) -> {
173+
lh.addChangeListener(control.focusedProperty(), (op) -> {
173174
// Fix for the regression noted in a comment in RT-29885.
174-
((FakeFocusTextField)textField).setFakeFocus(hasFocus);
175+
((FakeFocusTextField)textField).setFakeFocus(control.isFocused());
175176
});
176177

177-
control.addEventFilter(KeyEvent.ANY, ke -> {
178+
lh.addEventFilter(control, KeyEvent.ANY, (ke) -> {
178179
if (control.isEditable()) {
179180
// This prevents a stack overflow from our rebroadcasting of the
180181
// event to the textfield that occurs in the final else statement
@@ -204,14 +205,15 @@ public void executeAccessibleAction(AccessibleAction action, Object... parameter
204205
// Spinner control. Without this the up/down/left/right arrow keys don't
205206
// work when you click inside the TextField area (but they do in the case
206207
// of tabbing in).
207-
textField.addEventFilter(KeyEvent.ANY, ke -> {
208+
lh.addEventFilter(textField, KeyEvent.ANY, (ke) -> {
208209
if (! control.isEditable() || isIncDecKeyEvent(ke)) {
209210
control.fireEvent(ke.copyFor(control, control));
210211
ke.consume();
211212
}
212213
});
213214

214-
textField.focusedProperty().addListener((ov, t, hasFocus) -> {
215+
lh.addChangeListener(textField.focusedProperty(), (op) -> {
216+
boolean hasFocus = textField.isFocused();
215217
// Fix for RT-29885
216218
control.getProperties().put("FOCUSED", hasFocus);
217219
// --- end of RT-29885
@@ -229,7 +231,6 @@ public void executeAccessibleAction(AccessibleAction action, Object... parameter
229231

230232
textField.focusTraversableProperty().bind(control.editableProperty());
231233

232-
233234
// Following code borrowed from ComboBoxPopupControl, to resolve the
234235
// issue initially identified in RT-36902, but specifically (for Spinner)
235236
// identified in RT-40625
@@ -261,13 +262,27 @@ private boolean isIncDecKeyEvent(KeyEvent ke) {
261262
* *
262263
**************************************************************************/
263264

265+
@Override
266+
public void install() {
267+
// when replacing the skin, the textField (which comes from the control), must first be uninstalled
268+
// by the old skin in its dispose(), followed by (re-)adding it here.
269+
getChildren().add(textField);
270+
}
271+
264272
/** {@inheritDoc} */
265-
@Override public void dispose() {
266-
super.dispose();
273+
@Override
274+
public void dispose() {
275+
if (getSkinnable() == null) {
276+
return;
277+
}
278+
279+
getChildren().removeAll(textField, incrementArrowButton, decrementArrowButton);
267280

268281
if (behavior != null) {
269282
behavior.dispose();
270283
}
284+
285+
super.dispose();
271286
}
272287

273288
/** {@inheritDoc} */

modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/SkinMemoryLeakTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ public static Collection<Object[]> data() {
235235
PasswordField.class,
236236

237237
//
238-
Spinner.class,
238+
//Spinner.class,
239239

240240
//
241241
//SplitPane.class,

modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/SpinnerSkinTest.java

+8
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,12 @@ public void shouldPositionArrowsSplitTopAndBottom() {
141141
assertEquals(new BoundingBox(PADDING_LEFT, PADDING_TOP + HEIGHT - tallest, WIDTH, tallest), decrementArrowButton.getBoundsInParent());
142142
assertEquals(new BoundingBox(PADDING_LEFT, PADDING_TOP, WIDTH, tallest), incrementArrowButton.getBoundsInParent());
143143
}
144+
145+
/** Tests JDK-8245145: IAE when replacing skins */
146+
@Test
147+
public void testSpinnerSkin() {
148+
Spinner<?> spinner = new Spinner<>();
149+
spinner.setSkin(new SpinnerSkin<>(spinner));
150+
spinner.setSkin(new SpinnerSkin<>(spinner));
151+
}
144152
}

0 commit comments

Comments
 (0)