1
1
/*
2
- * Copyright (c) 2012, 2021 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2012, 2022 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
25
25
26
26
package javafx .scene .control .skin ;
27
27
28
- import com .sun .javafx .scene .control .TreeTableViewBackingList ;
29
- import javafx .event .WeakEventHandler ;
30
- import javafx .scene .control .*;
31
-
32
- import com .sun .javafx .scene .control .behavior .TreeTableViewBehavior ;
33
-
34
28
import java .lang .ref .WeakReference ;
35
29
import java .util .ArrayList ;
36
30
import java .util .List ;
43
37
import javafx .scene .AccessibleAction ;
44
38
import javafx .scene .AccessibleAttribute ;
45
39
import javafx .scene .Node ;
46
- import javafx .scene .control .TreeItem .TreeModificationEvent ;
40
+ import javafx .scene .control .Control ;
41
+ import javafx .scene .control .TreeItem ;
42
+ import javafx .scene .control .TreeTableCell ;
43
+ import javafx .scene .control .TreeTableColumn ;
44
+ import javafx .scene .control .TreeTablePosition ;
45
+ import javafx .scene .control .TreeTableRow ;
46
+ import javafx .scene .control .TreeTableView ;
47
47
import javafx .scene .input .MouseEvent ;
48
48
import javafx .scene .layout .StackPane ;
49
49
50
+ import com .sun .javafx .scene .control .IDisconnectable ;
51
+ import com .sun .javafx .scene .control .ListenerHelper ;
52
+ import com .sun .javafx .scene .control .TreeTableViewBackingList ;
53
+ import com .sun .javafx .scene .control .behavior .TreeTableViewBehavior ;
54
+
50
55
/**
51
56
* Default skin implementation for the {@link TreeTableView} control.
52
57
*
@@ -66,46 +71,7 @@ public class TreeTableViewSkin<T> extends TableViewSkinBase<T, TreeItem<T>, Tree
66
71
67
72
private WeakReference <TreeItem <T >> weakRootRef ;
68
73
private final TreeTableViewBehavior <T > behavior ;
69
-
70
-
71
-
72
- /* *************************************************************************
73
- * *
74
- * Listeners *
75
- * *
76
- **************************************************************************/
77
-
78
- private EventHandler <TreeItem .TreeModificationEvent <T >> rootListener = e -> {
79
- if (e .wasAdded () && e .wasRemoved () && e .getAddedSize () == e .getRemovedSize ()) {
80
- // Fix for RT-14842, where the children of a TreeItem were changing,
81
- // but because the overall item count was staying the same, there was
82
- // no event being fired to the skin to be informed that the items
83
- // had changed. So, here we just watch for the case where the number
84
- // of items being added is equal to the number of items being removed.
85
- markItemCountDirty ();
86
- getSkinnable ().requestLayout ();
87
- } else if (e .getEventType ().equals (TreeItem .valueChangedEvent ())) {
88
- // Fix for RT-14971 and RT-15338.
89
- requestRebuildCells ();
90
- } else {
91
- // Fix for RT-20090. We are checking to see if the event coming
92
- // from the TreeItem root is an event where the count has changed.
93
- EventType <?> eventType = e .getEventType ();
94
- while (eventType != null ) {
95
- if (eventType .equals (TreeItem .<T >expandedItemCountChangeEvent ())) {
96
- markItemCountDirty ();
97
- getSkinnable ().requestLayout ();
98
- break ;
99
- }
100
- eventType = eventType .getSuperType ();
101
- }
102
- }
103
-
104
- // fix for RT-37853
105
- getSkinnable ().edit (-1 , null );
106
- };
107
-
108
- private WeakEventHandler <TreeModificationEvent <T >> weakRootListener ;
74
+ private IDisconnectable rootListener ;
109
75
110
76
111
77
@@ -127,13 +93,14 @@ public TreeTableViewSkin(final TreeTableView<T> control) {
127
93
128
94
// install default input map for the TreeTableView control
129
95
behavior = new TreeTableViewBehavior <>(control );
130
- // control.setInputMap(behavior.getInputMap());
131
96
132
97
flow .setFixedCellSize (control .getFixedCellSize ());
133
98
flow .setCellFactory (flow -> createCell ());
134
99
135
100
setRoot (getSkinnable ().getRoot ());
136
101
102
+ ListenerHelper lh = ListenerHelper .get (this );
103
+
137
104
EventHandler <MouseEvent > ml = event -> {
138
105
// This ensures that the table maintains the focus, even when the vbar
139
106
// and hbar controls inside the flow are clicked. Without this, the
@@ -144,8 +111,8 @@ public TreeTableViewSkin(final TreeTableView<T> control) {
144
111
control .requestFocus ();
145
112
}
146
113
};
147
- flow .getVbar (). addEventFilter ( MouseEvent .MOUSE_PRESSED , ml );
148
- flow .getHbar (). addEventFilter ( MouseEvent .MOUSE_PRESSED , ml );
114
+ lh . addEventFilter ( flow .getVbar (), MouseEvent .MOUSE_PRESSED , ml );
115
+ lh . addEventFilter ( flow .getHbar (), MouseEvent .MOUSE_PRESSED , ml );
149
116
150
117
// init the behavior 'closures'
151
118
behavior .setOnFocusPreviousRow (() -> onFocusAboveCell ());
@@ -161,13 +128,13 @@ public TreeTableViewSkin(final TreeTableView<T> control) {
161
128
behavior .setOnFocusLeftCell (() -> onFocusLeftCell ());
162
129
behavior .setOnFocusRightCell (() -> onFocusRightCell ());
163
130
164
- registerChangeListener (control .rootProperty (), e -> {
131
+ lh . addChangeListener (control .rootProperty (), ( ev ) -> {
165
132
// fix for RT-37853
166
133
getSkinnable ().edit (-1 , null );
167
-
168
134
setRoot (getSkinnable ().getRoot ());
169
135
});
170
- registerChangeListener (control .showRootProperty (), e -> {
136
+
137
+ lh .addChangeListener (control .showRootProperty (), (ev ) -> {
171
138
// if we turn off showing the root, then we must ensure the root
172
139
// is expanded - otherwise we end up with no visible items in
173
140
// the tree.
@@ -177,11 +144,19 @@ public TreeTableViewSkin(final TreeTableView<T> control) {
177
144
// update the item count in the flow and behavior instances
178
145
updateItemCount ();
179
146
});
180
- registerChangeListener (control .rowFactoryProperty (), e -> flow .recreateCells ());
181
- registerChangeListener (control .expandedItemCountProperty (), e -> markItemCountDirty ());
182
- registerChangeListener (control .fixedCellSizeProperty (), e -> flow .setFixedCellSize (getSkinnable ().getFixedCellSize ()));
183
- }
184
147
148
+ lh .addChangeListener (control .rowFactoryProperty (), (ev ) -> {
149
+ flow .recreateCells ();
150
+ });
151
+
152
+ lh .addChangeListener (control .expandedItemCountProperty (), (ev ) -> {
153
+ markItemCountDirty ();
154
+ });
155
+
156
+ lh .addChangeListener (control .fixedCellSizeProperty (), (ev ) -> {
157
+ flow .setFixedCellSize (getSkinnable ().getFixedCellSize ());
158
+ });
159
+ }
185
160
186
161
187
162
/* *************************************************************************
@@ -191,12 +166,20 @@ public TreeTableViewSkin(final TreeTableView<T> control) {
191
166
**************************************************************************/
192
167
193
168
/** {@inheritDoc} */
194
- @ Override public void dispose () {
195
- super .dispose ();
169
+ @ Override
170
+ public void dispose () {
171
+ flow .setCellFactory (null );
172
+
173
+ if (rootListener != null ) {
174
+ rootListener .disconnect ();
175
+ rootListener = null ;
176
+ }
196
177
197
178
if (behavior != null ) {
198
179
behavior .dispose ();
199
180
}
181
+
182
+ super .dispose ();
200
183
}
201
184
202
185
/** {@inheritDoc} */
@@ -299,13 +282,43 @@ private TreeItem<T> getRoot() {
299
282
return weakRootRef == null ? null : weakRootRef .get ();
300
283
}
301
284
private void setRoot (TreeItem <T > newRoot ) {
302
- if (getRoot () != null && weakRootListener != null ) {
303
- getRoot ().removeEventHandler (TreeItem .<T >treeNotificationEvent (), weakRootListener );
285
+ if (rootListener != null ) {
286
+ rootListener .disconnect ();
287
+ rootListener = null ;
304
288
}
305
289
weakRootRef = new WeakReference <>(newRoot );
306
290
if (getRoot () != null ) {
307
- weakRootListener = new WeakEventHandler <>(rootListener );
308
- getRoot ().addEventHandler (TreeItem .<T >treeNotificationEvent (), weakRootListener );
291
+ // TODO I wonder if it might be possible for the root ref to get collected between these two lines
292
+ // which would throw an NPE. Perhaps we should simply use newRoot instance instead of getRoot().
293
+ rootListener = ListenerHelper .get (this ).addEventHandler (getRoot (), TreeItem .<T >treeNotificationEvent (), e -> {
294
+ if (e .wasAdded () && e .wasRemoved () && e .getAddedSize () == e .getRemovedSize ()) {
295
+ // Fix for RT-14842, where the children of a TreeItem were changing,
296
+ // but because the overall item count was staying the same, there was
297
+ // no event being fired to the skin to be informed that the items
298
+ // had changed. So, here we just watch for the case where the number
299
+ // of items being added is equal to the number of items being removed.
300
+ markItemCountDirty ();
301
+ getSkinnable ().requestLayout ();
302
+ } else if (e .getEventType ().equals (TreeItem .valueChangedEvent ())) {
303
+ // Fix for RT-14971 and RT-15338.
304
+ requestRebuildCells ();
305
+ } else {
306
+ // Fix for RT-20090. We are checking to see if the event coming
307
+ // from the TreeItem root is an event where the count has changed.
308
+ EventType <?> eventType = e .getEventType ();
309
+ while (eventType != null ) {
310
+ if (eventType .equals (TreeItem .<T >expandedItemCountChangeEvent ())) {
311
+ markItemCountDirty ();
312
+ getSkinnable ().requestLayout ();
313
+ break ;
314
+ }
315
+ eventType = eventType .getSuperType ();
316
+ }
317
+ }
318
+
319
+ // fix for RT-37853
320
+ getSkinnable ().edit (-1 , null );
321
+ });
309
322
}
310
323
311
324
updateItemCount ();
0 commit comments