@@ -267,10 +267,22 @@ public TabPaneSkin(TabPane control) {
267267
268268 /** {@inheritDoc} */
269269 @ Override public void dispose () {
270+ if (getSkinnable () == null ) return ;
271+
270272 if (selectionModel != null ) {
271273 selectionModel .selectedItemProperty ().removeListener (weakSelectionChangeListener );
272274 selectionModel = null ;
273275 }
276+ getSkinnable ().getTabs ().removeListener (weakTabsListener );
277+ tabHeaderArea .dispose ();
278+
279+ // Control and Skin share the list of children, so children that are
280+ // added by Skin are actually added to control's list of children,
281+ // so a skin should remove the children that it adds.
282+ getChildren ().remove (tabHeaderArea );
283+ for (Tab tab : getSkinnable ().getTabs ()) {
284+ removeTabContent (tab );
285+ }
274286
275287 super .dispose ();
276288
@@ -499,7 +511,7 @@ private void removeTabs(List<? extends Tab> removedList) {
499511 if (tabRegion != null ) {
500512 tabRegion .isClosing = true ;
501513
502- tabRegion .removeListeners ( tab );
514+ tabRegion .dispose ( );
503515 removeTabContent (tab );
504516
505517 EventHandler <ActionEvent > cleanup = ae -> {
@@ -579,8 +591,10 @@ private void addTabs(List<? extends Tab> addedList, int from) {
579591 }
580592 }
581593
594+ ListChangeListener <Tab > tabsListener ;
595+ WeakListChangeListener <Tab > weakTabsListener ;
582596 private void initializeTabListener () {
583- getSkinnable (). getTabs (). addListener (( ListChangeListener < Tab >) c -> {
597+ tabsListener = c -> {
584598 List <Tab > tabsToRemove = new ArrayList <>();
585599 List <Tab > tabsToAdd = new ArrayList <>();
586600
@@ -659,7 +673,9 @@ private void initializeTabListener() {
659673
660674 // Fix for RT-34692
661675 getSkinnable ().requestLayout ();
662- });
676+ };
677+ weakTabsListener = new WeakListChangeListener <>(tabsListener );
678+ getSkinnable ().getTabs ().addListener (weakTabsListener );
663679 }
664680
665681 private void addTabContent (Tab tab ) {
@@ -673,14 +689,18 @@ private void addTabContent(Tab tab) {
673689 private void removeTabContent (Tab tab ) {
674690 for (TabContentRegion contentRegion : tabContentRegions ) {
675691 if (contentRegion .getTab ().equals (tab )) {
676- contentRegion .removeListeners (tab );
677- getChildren ().remove (contentRegion );
678- tabContentRegions .remove (contentRegion );
692+ removeTabContent (contentRegion );
679693 break ;
680694 }
681695 }
682696 }
683697
698+ private void removeTabContent (TabContentRegion contentRegion ) {
699+ contentRegion .dispose ();
700+ tabContentRegions .remove (contentRegion );
701+ getChildren ().remove (contentRegion );
702+ }
703+
684704 private void updateTabPosition () {
685705 tabHeaderArea .invalidateScrollOffset ();
686706 getSkinnable ().applyCss ();
@@ -1208,6 +1228,14 @@ private double firstTabIndent() {
12081228 positionInArea (controlButtons , controlStartX , controlStartY , btnWidth , btnHeight ,
12091229 /*baseline ignored*/ 0 , HPos .CENTER , VPos .CENTER );
12101230 }
1231+
1232+ void dispose () {
1233+ for (Node child : headersRegion .getChildren ()) {
1234+ TabHeaderSkin header = (TabHeaderSkin ) child ;
1235+ header .dispose ();
1236+ }
1237+ controlButtons .dispose ();
1238+ }
12111239 } /* End TabHeaderArea */
12121240
12131241
@@ -1495,7 +1523,7 @@ public void handle(MouseEvent me) {
14951523 if (me .getButton ().equals (MouseButton .MIDDLE )) {
14961524 if (showCloseButton ()) {
14971525 if (behavior .canCloseTab (tab )) {
1498- removeListeners ( tab );
1526+ dispose ( );
14991527 behavior .closeTab (tab );
15001528 }
15011529 }
@@ -1541,10 +1569,9 @@ private boolean showCloseButton() {
15411569 }
15421570 };
15431571
1544- private void removeListeners (Tab tab ) {
1572+ private void dispose () {
1573+ tab .getStyleClass ().removeListener (weakStyleClassListener );
15451574 listener .dispose ();
1546- inner .getChildren ().clear ();
1547- getChildren ().clear ();
15481575 setOnContextMenuRequested (null );
15491576 setOnMousePressed (null );
15501577 }
@@ -1693,7 +1720,7 @@ private void updateContent() {
16931720 }
16941721 }
16951722
1696- private void removeListeners ( Tab tab ) {
1723+ public void dispose ( ) {
16971724 tab .selectedProperty ().removeListener (weakTabSelectedListener );
16981725 tab .contentProperty ().removeListener (weakTabContentListener );
16991726 }
@@ -1785,11 +1812,8 @@ private void positionArrow(Pane btn, StackPane arrow, double x, double y, double
17851812
17861813 getChildren ().add (inner );
17871814
1788- tabPane .sideProperty ().addListener (valueModel -> {
1789- Side tabPosition = getSkinnable ().getSide ();
1790- downArrow .setRotate (tabPosition .equals (Side .BOTTOM )? 180.0F : 0.0F );
1791- });
1792- tabPane .getTabs ().addListener ((ListChangeListener <Tab >) c -> setupPopupMenu ());
1815+ tabPane .sideProperty ().addListener (weakSidePropListener );
1816+ tabPane .getTabs ().addListener (weakTabsListenerForPopup );
17931817 showControlButtons = false ;
17941818 if (isShowTabsMenu ()) {
17951819 showControlButtons = true ;
@@ -1798,6 +1822,21 @@ private void positionArrow(Pane btn, StackPane arrow, double x, double y, double
17981822 getProperties ().put (ContextMenu .class , popup );
17991823 }
18001824
1825+ InvalidationListener sidePropListener = e -> {
1826+ Side tabPosition = getSkinnable ().getSide ();
1827+ downArrow .setRotate (tabPosition .equals (Side .BOTTOM )? 180.0F : 0.0F );
1828+ };
1829+ ListChangeListener <Tab > tabsListenerForPopup = e -> setupPopupMenu ();
1830+ WeakInvalidationListener weakSidePropListener =
1831+ new WeakInvalidationListener (sidePropListener );
1832+ WeakListChangeListener weakTabsListenerForPopup =
1833+ new WeakListChangeListener <>(tabsListenerForPopup );
1834+
1835+ void dispose () {
1836+ getSkinnable ().sideProperty ().removeListener (weakSidePropListener );
1837+ getSkinnable ().getTabs ().removeListener (weakTabsListenerForPopup );
1838+ }
1839+
18011840 private boolean showTabsMenu = false ;
18021841
18031842 private void showTabsMenu (boolean value ) {
@@ -2058,11 +2097,7 @@ private void setupReordering(StackPane headersRegion) {
20582097 dragState = DragState .NONE ;
20592098 this .headersRegion = headersRegion ;
20602099 updateListeners ();
2061- getSkinnable ().tabDragPolicyProperty ().addListener ((observable , oldValue , newValue ) -> {
2062- if (oldValue != newValue ) {
2063- updateListeners ();
2064- }
2065- });
2100+ registerChangeListener (getSkinnable ().tabDragPolicyProperty (), inv -> updateListeners ());
20662101 }
20672102
20682103 private void handleHeaderMousePressed (MouseEvent event ) {
0 commit comments