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 }