1 /* 2 * Copyright (c) 2010, 2016, 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 javafx.scene.control.skin; 27 28 import javafx.scene.control.Control; 29 import javafx.scene.control.IndexedCell; 30 import javafx.scene.control.ScrollToEvent; 31 import javafx.scene.control.SkinBase; 32 33 /** 34 * Parent class to control skins whose contents are virtualized and scrollable. 35 * This class handles the interaction with the VirtualFlow class, which is the 36 * main class handling the virtualization of the contents of this container. 37 * 38 * @since 9 39 */ 40 public abstract class VirtualContainerBase<C extends Control, I extends IndexedCell> extends SkinBase<C> { 41 42 /*************************************************************************** 43 * * 44 * Private fields * 45 * * 46 **************************************************************************/ 47 48 private boolean itemCountDirty; 49 50 /** 51 * The virtualized container which handles the layout and scrolling of 52 * all the cells. 53 */ 54 private final VirtualFlow<I> flow; 55 56 57 58 /*************************************************************************** 59 * * 60 * Constructors * 61 * * 62 **************************************************************************/ 63 64 /** 65 * 66 * @param control 67 */ 68 public VirtualContainerBase(final C control) { 69 super(control); 70 flow = createVirtualFlow(); 71 72 control.addEventHandler(ScrollToEvent.scrollToTopIndex(), event -> { 73 // Fix for RT-24630: The row count in VirtualFlow was incorrect 74 // (normally zero), so the scrollTo call was misbehaving. 75 if (itemCountDirty) { 76 // update row count before we do a scroll 77 updateItemCount(); 78 itemCountDirty = false; 79 } 80 flow.scrollToTop(event.getScrollTarget()); 81 }); 82 } 83 84 85 86 /*************************************************************************** 87 * * 88 * Abstract API * 89 * * 90 **************************************************************************/ 91 92 /** 93 * Returns the total number of items in this container, including those 94 * that are currently hidden because they are out of view. 95 */ 96 protected abstract int getItemCount(); 97 98 /** 99 * This method is called when it is possible that the item count has changed (i.e. scrolling has occurred, 100 * the control has resized, etc). This method should recalculate the item count and store that for future 101 * use by the {@link #getItemCount} method. 102 */ 103 protected abstract void updateItemCount(); 104 105 106 107 /*************************************************************************** 108 * * 109 * Public API * 110 * * 111 **************************************************************************/ 112 113 /** 114 * Call this method to indicate that the item count should be updated on the next pulse. 115 */ 116 protected final void markItemCountDirty() { 117 itemCountDirty = true; 118 } 119 120 /** {@inheritDoc} */ 121 @Override protected void layoutChildren(double x, double y, double w, double h) { 122 checkState(); 123 } 124 125 126 127 /*************************************************************************** 128 * * 129 * Private methods * 130 * * 131 **************************************************************************/ 132 133 /** 134 * This enables skin subclasses to provide a custom VirtualFlow implementation, 135 * rather than have VirtualContainerBase instantiate the default instance. 136 */ 137 VirtualFlow<I> createVirtualFlow() { 138 return new VirtualFlow<>(); 139 } 140 141 final VirtualFlow<I> getVirtualFlow() { 142 return flow; 143 } 144 145 double getMaxCellWidth(int rowsToCount) { 146 return snappedLeftInset() + flow.getMaxCellWidth(rowsToCount) + snappedRightInset(); 147 } 148 149 double getVirtualFlowPreferredHeight(int rows) { 150 double height = 1.0; 151 152 for (int i = 0; i < rows && i < getItemCount(); i++) { 153 height += flow.getCellLength(i); 154 } 155 156 return height + snappedTopInset() + snappedBottomInset(); 157 } 158 159 void checkState() { 160 if (itemCountDirty) { 161 updateItemCount(); 162 itemCountDirty = false; 163 } 164 } 165 166 void requestRebuildCells() { 167 flow.rebuildCells(); 168 } 169 170 }