Skip to content

Commit 00a8646

Browse files
author
Jeanette Winzenburg
committed
8247576: Labeled/SkinBase: misbehavior on switching skin
Reviewed-by: arapte
1 parent c8d9c94 commit 00a8646

File tree

2 files changed

+146
-1
lines changed

2 files changed

+146
-1
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public abstract class LabeledSkinBase<C extends Labeled> extends SkinBase<C> {
118118
*/
119119
final InvalidationListener graphicPropertyChangedListener = valueModel -> {
120120
invalidText = true;
121-
if (getSkinnable() != null) getSkinnable().requestLayout();
121+
getSkinnable().requestLayout();
122122
};
123123

124124
private Rectangle textClip;
@@ -240,6 +240,17 @@ public LabeledSkinBase(final C labeled) {
240240
* *
241241
**************************************************************************/
242242

243+
@Override
244+
public void dispose() {
245+
if (graphic != null) {
246+
graphic.layoutBoundsProperty().removeListener(graphicPropertyChangedListener);
247+
graphic = null;
248+
}
249+
super.dispose();
250+
}
251+
252+
253+
243254
/**
244255
* Updates the children managed by LabeledSkinBase, which can be the Labeled
245256
* graphic and/or a Text node. Only those nodes which actually must
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package test.javafx.scene.control.skin;
27+
28+
import java.lang.ref.WeakReference;
29+
import java.util.Collection;
30+
import java.util.List;
31+
32+
import org.junit.After;
33+
import org.junit.Before;
34+
import org.junit.Test;
35+
import org.junit.runner.RunWith;
36+
import org.junit.runners.Parameterized;
37+
38+
import static javafx.scene.control.ControlShim.*;
39+
import static org.junit.Assert.*;
40+
import static test.com.sun.javafx.scene.control.infrastructure.ControlSkinFactory.*;
41+
42+
import javafx.scene.control.Button;
43+
import javafx.scene.control.CheckBox;
44+
import javafx.scene.control.Hyperlink;
45+
import javafx.scene.control.Label;
46+
import javafx.scene.control.Labeled;
47+
import javafx.scene.control.RadioButton;
48+
import javafx.scene.control.TitledPane;
49+
import javafx.scene.control.ToggleButton;
50+
import javafx.scene.shape.Rectangle;
51+
52+
/**
53+
* Test skin cleanup for Labeled JDK-8247576
54+
* <p>
55+
* This test is parameterized on class of Labeled.
56+
*
57+
*/
58+
@RunWith(Parameterized.class)
59+
public class SkinLabeledCleanupTest {
60+
61+
private Class<Labeled> labeledClass;
62+
private Labeled labeled;
63+
64+
/**
65+
* First step was cleanup of graphicListener: removed guard against null skinnable.
66+
*/
67+
@Test
68+
public void testLabeledGraphicDispose() {
69+
Rectangle graphic = (Rectangle) labeled.getGraphic();
70+
installDefaultSkin(labeled);
71+
labeled.getSkin().dispose();
72+
graphic.setWidth(500);
73+
}
74+
75+
@Test
76+
public void testMemoryLeakAlternativeSkin() {
77+
installDefaultSkin(labeled);
78+
WeakReference<?> weakRef = new WeakReference<>(replaceSkin(labeled));
79+
assertNotNull(weakRef.get());
80+
attemptGC(weakRef);
81+
assertEquals("Skin must be gc'ed", null, weakRef.get());
82+
}
83+
84+
//----------- parameterized
85+
86+
@Parameterized.Parameters //(name = "{index}: {0} ")
87+
public static Collection<Object[]> data() {
88+
List<Class> labeledClasses = List.of(
89+
Button.class,
90+
CheckBox.class,
91+
Hyperlink.class,
92+
Label.class,
93+
// MenuButton is-a Labeled but its skin is-not-a LabeledSkinBase
94+
// leaking has different reason/s
95+
// MenuButton.class,
96+
ToggleButton.class,
97+
RadioButton.class,
98+
TitledPane.class
99+
);
100+
return asArrays(labeledClasses);
101+
}
102+
103+
public SkinLabeledCleanupTest(Class<Labeled> labeledClass) {
104+
this.labeledClass = labeledClass;
105+
}
106+
107+
//---------------- setup/cleanup
108+
109+
@Test
110+
public void testSetupState() {
111+
assertNotNull(labeled);
112+
assertNotNull(labeled.getGraphic());
113+
}
114+
115+
@After
116+
public void cleanup() {
117+
Thread.currentThread().setUncaughtExceptionHandler(null);
118+
}
119+
120+
@Before
121+
public void setup() {
122+
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
123+
if (throwable instanceof RuntimeException) {
124+
throw (RuntimeException)throwable;
125+
} else {
126+
Thread.currentThread().getThreadGroup().uncaughtException(thread, throwable);
127+
}
128+
});
129+
130+
labeled = createControl(labeledClass);
131+
labeled.setGraphic(new Rectangle());
132+
}
133+
134+
}

0 commit comments

Comments
 (0)