3636import javafx .collections .ObservableList ;
3737import javafx .css .StyleOrigin ;
3838import javafx .css .StyleableObjectProperty ;
39- import javafx .geometry .Insets ;
4039import javafx .geometry .Pos ;
4140import javafx .scene .Node ;
4241import javafx .scene .Parent ;
@@ -95,11 +94,6 @@ public abstract class TableRowSkinBase<T,
9594 */
9695 static final Map <TableColumnBase <?,?>, Double > maxDisclosureWidthMap = new WeakHashMap <>();
9796
98- // Specifies the number of times we will call 'recreateCells()' before we blow
99- // out the cellsMap structure and rebuild all cells. This helps to prevent
100- // against memory leaks in certain extreme circumstances.
101- private static final int DEFAULT_FULL_REFRESH_COUNTER = 100 ;
102-
10397
10498 /* *************************************************************************
10599 * *
@@ -113,21 +107,13 @@ public abstract class TableRowSkinBase<T,
113107 * efficiency we create cells for all columns, even if they aren't visible,
114108 * and we only create new cells if we don't already have it cached in this
115109 * map.
116- *
117- * Note that this means that it is possible for this map to therefore be
118- * a memory leak if an application uses TableView and is creating and removing
119- * a large number of tableColumns. This is mitigated in the recreateCells()
120- * function below - refer to that to learn more.
121110 */
122111 WeakHashMap <TableColumnBase , Reference <R >> cellsMap ;
123112
124113 // This observableArrayList contains the currently visible table cells for this row.
125114 final List <R > cells = new ArrayList <>();
126115
127- private int fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER ;
128-
129116 boolean isDirty = false ;
130- boolean updateCells = false ;
131117
132118 // FIXME: replace cached values with direct lookup - JDK-8277000
133119 double fixedCellSize ;
@@ -152,7 +138,7 @@ public TableRowSkinBase(C control) {
152138 getSkinnable ().setPickOnBounds (false );
153139
154140 recreateCells ();
155- updateCells (true );
141+ updateCells ();
156142
157143 // init bindings
158144 // watches for any change in the leaf columns observableArrayList - this will indicate
@@ -176,7 +162,7 @@ public TableRowSkinBase(C control) {
176162 * *
177163 **************************************************************************/
178164
179- private void updateLeafColumns () {
165+ void updateLeafColumns () {
180166 isDirty = true ;
181167 getSkinnable ().requestLayout ();
182168 }
@@ -289,7 +275,6 @@ protected ObjectProperty<Node> graphicProperty() {
289275 // earlier rows to update themselves to take into account
290276 // this increased indentation.
291277 final VirtualFlow <C > flow = getVirtualFlow ();
292- final int thisIndex = getSkinnable ().getIndex ();
293278 for (int i = 0 ; i < flow .cells .size (); i ++) {
294279 C cell = flow .cells .get (i );
295280 if (cell == null || cell .isEmpty ()) continue ;
@@ -318,10 +303,13 @@ protected ObjectProperty<Node> graphicProperty() {
318303 int index = control .getIndex ();
319304 if (index < 0 /* || row >= itemsProperty().get().size()*/ ) return ;
320305
306+ VirtualFlow <C > virtualFlow = getVirtualFlow ();
321307 for (int column = 0 , max = cells .size (); column < max ; column ++) {
322308 R tableCell = cells .get (column );
323309 TableColumnBase <T , ?> tableColumn = getTableColumn (tableCell );
324310
311+ width = snapSizeX (tableColumn .getWidth ());
312+
325313 boolean isVisible = true ;
326314 if (fixedCellSizeEnabled ) {
327315 // we determine if the cell is visible, and if not we have the
@@ -333,7 +321,7 @@ protected ObjectProperty<Node> graphicProperty() {
333321 // provided by the developer, and this means that we do not have
334322 // to concern ourselves with the possibility that the height
335323 // may be variable and / or dynamic.
336- isVisible = isColumnPartiallyOrFullyVisible (tableColumn );
324+ isVisible = isColumnPartiallyOrFullyVisible (x , width , virtualFlow );
337325
338326 y = 0 ;
339327 height = fixedCellSize ;
@@ -342,12 +330,9 @@ protected ObjectProperty<Node> graphicProperty() {
342330 }
343331
344332 if (isVisible ) {
345- if (fixedCellSizeEnabled && tableCell .getParent () == null ) {
333+ if (tableCell .getParent () == null ) {
346334 getChildren ().add (tableCell );
347335 }
348- // Note: prefWidth() has to be called only after the tableCell is added to the tableRow, if it wasn't
349- // already. Otherwise, it might not have its skin yet, and its pref width is therefore 0.
350- width = tableCell .prefWidth (height );
351336
352337 // Added for JDK-8115536, and then updated for JDK-8122708.
353338 // We change the alignment from CENTER_LEFT to TOP_LEFT if the
@@ -419,11 +404,7 @@ protected ObjectProperty<Node> graphicProperty() {
419404 // This does not appear to impact performance...
420405 tableCell .requestLayout ();
421406 } else {
422- width = tableCell .prefWidth (height );
423- if (fixedCellSizeEnabled ) {
424- // we only add/remove to the scenegraph if the fixed cell
425- // length support is enabled - otherwise we keep all
426- // TableCells in the scenegraph
407+ if (tableCell .getParent () != null ) {
427408 getChildren ().remove (tableCell );
428409 }
429410 }
@@ -473,21 +454,9 @@ boolean isShowRoot() {
473454 return true ;
474455 }
475456
476- void updateCells (boolean resetChildren ) {
477- // To avoid a potential memory leak (when the TableColumns in the
478- // TableView are created/inserted/removed/deleted, we have a 'refresh
479- // counter' that when we reach 0 will delete all cells in this row
480- // and recreate all of them.
481- if (resetChildren ) {
482- if (fullRefreshCounter == 0 ) {
483- recreateCells ();
484- }
485- fullRefreshCounter --;
486- }
487-
457+ void updateCells () {
488458 // if clear isn't called first, we can run into situations where the
489459 // cells aren't updated properly.
490- final boolean cellsEmpty = cells .isEmpty ();
491460 cells .clear ();
492461
493462 final C skinnable = getSkinnable ();
@@ -518,23 +487,7 @@ void updateCells(boolean resetChildren) {
518487 cells .add (cell );
519488 }
520489
521- // update children of each row
522- if (fixedCellSizeEnabled ) {
523- // we leave the adding / removing up to the layoutChildren method mostly, but here we remove any children
524- // cells that refer to columns that are removed or not visible.
525- List <Node > toRemove = new ArrayList <>();
526- for (Node cell : getChildren ()) {
527- if (!(cell instanceof IndexedCell )) continue ;
528- TableColumnBase <T , ?> tableColumn = getTableColumn ((R ) cell );
529- if (!getVisibleLeafColumns ().contains (tableColumn )) {
530- toRemove .add (cell );
531- }
532- }
533- getChildren ().removeAll (toRemove );
534- }
535- if (resetChildren || cellsEmpty ) {
536- getChildren ().setAll (cells );
537- }
490+ getChildren ().setAll (cells );
538491 }
539492
540493 VirtualFlow <C > getVirtualFlow () {
@@ -630,12 +583,8 @@ VirtualFlow<C> getVirtualFlow() {
630583
631584 final void checkState () {
632585 if (isDirty ) {
633- updateCells (true );
586+ updateCells ();
634587 isDirty = false ;
635- updateCells = false ;
636- } else if (updateCells ) {
637- updateCells (false );
638- updateCells = false ;
639588 }
640589 }
641590
@@ -655,33 +604,18 @@ void setDirty(boolean dirty) {
655604 * *
656605 **************************************************************************/
657606
658- private boolean isColumnPartiallyOrFullyVisible (TableColumnBase col ) {
659- if ( col == null || ! col . isVisible ()) return false ;
607+ private boolean isColumnPartiallyOrFullyVisible (double start , double width , VirtualFlow < C > virtualFlow ) {
608+ double end = start + width ;
660609
661- final VirtualFlow <?> virtualFlow = getVirtualFlow ();
662610 double scrollX = virtualFlow == null ? 0.0 : virtualFlow .getHbar ().getValue ();
611+ double headerWidth = virtualFlow == null ? 0.0 : virtualFlow .getViewportBreadth ();
612+ double virtualFlowWidth = headerWidth + scrollX ;
663613
664- // work out where this column header is, and it's width (start -> end)
665- double start = 0 ;
666- final ObservableList <? extends TableColumnBase > visibleLeafColumns = getVisibleLeafColumns ();
667- for (int i = 0 , max = visibleLeafColumns .size (); i < max ; i ++) {
668- TableColumnBase <?,?> c = visibleLeafColumns .get (i );
669- if (c .equals (col )) break ;
670- start += c .getWidth ();
671- }
672- double end = start + col .getWidth ();
673-
674- // determine the width of the table
675- final Insets padding = getSkinnable ().getPadding ();
676- double headerWidth = getSkinnable ().getWidth () - padding .getLeft () + padding .getRight ();
677-
678- return (start >= scrollX || end > scrollX ) && (start < (headerWidth + scrollX ) || end <= (headerWidth + scrollX ));
614+ return (start >= scrollX || end > scrollX ) && (start < virtualFlowWidth || end <= virtualFlowWidth );
679615 }
680616
681617 private void requestCellUpdate () {
682- updateCells = true ;
683618 getSkinnable ().requestLayout ();
684-
685619 // update the index of all children cells (JDK-8119094).
686620 // Note that we do this after the TableRow item has been updated,
687621 // rather than when the TableRow index has changed (as this will be
@@ -713,7 +647,6 @@ private void recreateCells() {
713647 ObservableList <? extends TableColumnBase /*<T,?>*/ > columns = getVisibleLeafColumns ();
714648
715649 cellsMap = new WeakHashMap <>(columns .size ());
716- fullRefreshCounter = DEFAULT_FULL_REFRESH_COUNTER ;
717650 getChildren ().clear ();
718651
719652 for (TableColumnBase col : columns ) {
0 commit comments