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 the 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 * @return the total number of items in this container 96 */ 97 protected abstract int getItemCount(); 98 99 /** 100 * This method is called when it is possible that the item count has changed (i.e. scrolling has occurred, 101 * the control has resized, etc). This method should recalculate the item count and store that for future 102 * use by the {@link #getItemCount} method. 103 */ 104 protected abstract void updateItemCount(); 105 106 107 108 /*************************************************************************** 109 * * 110 * Public API * 111 * * 112 **************************************************************************/ 113 114 /** 115 * Call this method to indicate that the item count should be updated on the next pulse. 116 */ 117 protected final void markItemCountDirty() { 118 itemCountDirty = true; 119 } 120 121 /** {@inheritDoc} */ 122 @Override protected void layoutChildren(double x, double y, double w, double h) { 123 checkState(); 124 } 125 126 127 128 /*************************************************************************** 129 * * 130 * Private methods * 131 * * 132 **************************************************************************/ 133 134 /** 135 * This enables skin subclasses to provide a custom VirtualFlow implementation, 136 * rather than have VirtualContainerBase instantiate the default instance. 137 */ 138 VirtualFlow<I> createVirtualFlow() { 139 return new VirtualFlow<>(); 140 } 141 142 final VirtualFlow<I> getVirtualFlow() { 143 return flow; 144 } 145 146 double getMaxCellWidth(int rowsToCount) { 147 return snappedLeftInset() + flow.getMaxCellWidth(rowsToCount) + snappedRightInset(); 148 } 149 150 double getVirtualFlowPreferredHeight(int rows) { 151 double height = 1.0; 152 153 for (int i = 0; i < rows && i < getItemCount(); i++) { 154 height += flow.getCellLength(i); 155 } 156 157 return height + snappedTopInset() + snappedBottomInset(); 158 } 159 160 void checkState() { 161 if (itemCountDirty) { 162 updateItemCount(); 163 itemCountDirty = false; 164 } 165 } 166 167 void requestRebuildCells() { 168 flow.rebuildCells(); 169 } 170 171 }