modules/controls/src/main/java/javafx/scene/control/skin/TreeTableRowSkin.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization


   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 com.sun.javafx.scene.control.skin;
  27 


  28 import javafx.collections.FXCollections;
  29 import javafx.scene.control.Control;
  30 import javafx.scene.control.TableColumnBase;
  31 import javafx.scene.control.TreeItem;
  32 import javafx.scene.control.TreeTableCell;
  33 import javafx.scene.control.TreeTableColumn;
  34 import javafx.scene.control.TreeTablePosition;
  35 import javafx.scene.control.TreeTableRow;
  36 import javafx.scene.control.TreeTableView;
  37 
  38 import java.util.ArrayList;
  39 import java.util.Collections;
  40 import java.util.List;
  41 
  42 import javafx.beans.property.DoubleProperty;
  43 import javafx.scene.AccessibleAttribute;
  44 import javafx.scene.Node;
  45 import javafx.css.StyleableDoubleProperty;
  46 import javafx.css.CssMetaData;
  47 
  48 import com.sun.javafx.css.converters.SizeConverter;
  49 import com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler;
  50 import com.sun.javafx.scene.control.behavior.TreeTableRowBehavior;
  51 
  52 import javafx.beans.property.ObjectProperty;
  53 import javafx.beans.property.SimpleObjectProperty;
  54 import javafx.beans.value.WritableValue;
  55 import javafx.collections.ObservableList;
  56 import javafx.css.Styleable;
  57 import javafx.css.StyleableProperty;
  58 
  59 public class TreeTableRowSkin<T> extends TableRowSkinBase<TreeItem<T>, TreeTableRow<T>, TreeTableRowBehavior<T>, TreeTableCell<T,?>> {






  60 
  61     /***************************************************************************
  62      *                                                                         *
  63      * Private Fields                                                          *
  64      *                                                                         *
  65      **************************************************************************/
  66 
  67     // maps into the TreeTableViewSkin items property via
  68     // TreeTableViewSkin.treeItemToListMap
  69     private SimpleObjectProperty<ObservableList<TreeItem<T>>> itemsProperty;
  70     private TreeItem<?> treeItem;
  71     private boolean disclosureNodeDirty = true;
  72     private Node graphic;

  73 
  74     private TreeTableViewSkin treeTableViewSkin;
  75 
  76     private boolean childrenDirty = false;
  77 
  78 
  79 
  80     /***************************************************************************
  81      *                                                                         *
  82      * Constructors                                                            *
  83      *                                                                         *
  84      **************************************************************************/
  85     







  86     public TreeTableRowSkin(TreeTableRow<T> control) {
  87         super(control, new TreeTableRowBehavior<T>(control));
  88         
  89         super.init(control);


  90         
  91         updateTreeItem();
  92         updateTableViewSkin();
  93 
  94         registerChangeListener(control.treeTableViewProperty(), "TREE_TABLE_VIEW");
  95         registerChangeListener(control.indexProperty(), "INDEX");
  96         registerChangeListener(control.treeItemProperty(), "TREE_ITEM");
  97         registerChangeListener(control.getTreeTableView().treeColumnProperty(), "TREE_COLUMN");









  98     }
  99 
 100 
 101 
 102     /***************************************************************************
 103      *                                                                         *
 104      * Listeners                                                               *
 105      *                                                                         *
 106      **************************************************************************/
 107 
 108     private MultiplePropertyChangeListenerHandler treeItemListener = new MultiplePropertyChangeListenerHandler(p -> {
 109         if ("GRAPHIC".equals(p)) {
 110             disclosureNodeDirty = true;
 111             getSkinnable().requestLayout();
 112         }
 113         return null;
 114     });
 115 
 116 
 117 
 118     /***************************************************************************
 119      *                                                                         *
 120      * Properties                                                              *
 121      *                                                                         *
 122      **************************************************************************/
 123 
 124     /**
 125      * The amount of space to multiply by the treeItem.level to get the left
 126      * margin for this tree cell. This is settable from CSS
 127      */
 128     private DoubleProperty indent = null;
 129     public final void setIndent(double value) { indentProperty().set(value); }
 130     public final double getIndent() { return indent == null ? 10.0 : indent.get(); }
 131     public final DoubleProperty indentProperty() { 
 132         if (indent == null) {
 133             indent = new StyleableDoubleProperty(10.0) {
 134                 @Override public Object getBean() {
 135                     return TreeTableRowSkin.this;
 136                 }
 137 
 138                 @Override public String getName() {
 139                     return "indent";
 140                 }
 141 
 142                 @Override public CssMetaData<TreeTableRow<?>,Number> getCssMetaData() {
 143                     return TreeTableRowSkin.StyleableProperties.INDENT;
 144                 }
 145             };
 146         }
 147         return indent; 
 148     }
 149 
 150 
 151 
 152     /***************************************************************************
 153      *                                                                         *
 154      * Public Methods                                                          *
 155      *                                                                         *
 156      **************************************************************************/
 157 
 158     @Override protected void handleControlPropertyChanged(String p) {
 159         super.handleControlPropertyChanged(p);

 160 
 161         if ("TREE_ABLE_VIEW".equals(p)) {
 162             updateTableViewSkin();
 163         } else if ("INDEX".equals(p)) {
 164             updateCells = true;
 165         } else if ("TREE_ITEM".equals(p)) {
 166             updateTreeItem();
 167             isDirty = true;
 168         } else if ("TREE_COLUMN".equals(p)) {
 169             // Fix for RT-27782: Need to set isDirty to true, rather than the
 170             // cheaper updateCells, as otherwise the text indentation will not
 171             // be recalculated in TreeTableCellSkin.leftLabelPadding()
 172             isDirty = true;
 173             getSkinnable().requestLayout();
 174         }
 175     }
 176 

 177     @Override protected void updateChildren() {
 178         super.updateChildren();
 179 
 180         updateDisclosureNodeAndGraphic();
 181 
 182         if (childrenDirty) {
 183             childrenDirty = false;
 184             if (cells.isEmpty()) {
 185                 getChildren().clear();
 186             } else {
 187                 // TODO we can optimise this by only showing cells that are
 188                 // visible based on the table width and the amount of horizontal
 189                 // scrolling.
 190                 getChildren().addAll(cells);
 191             }
 192         }
 193     }
 194 

 195     @Override protected void layoutChildren(double x, double y, double w, double h) {
 196         if (disclosureNodeDirty) {
 197             updateDisclosureNodeAndGraphic();
 198             disclosureNodeDirty = false;
 199         }
 200 
 201         Node disclosureNode = getDisclosureNode();
 202         if (disclosureNode != null && disclosureNode.getScene() == null) {
 203             updateDisclosureNodeAndGraphic();
 204         }
 205 
 206         super.layoutChildren(x, y, w, h);
 207     }
 208 
 209     @Override protected TreeTableCell<T, ?> getCell(TableColumnBase tcb) {









 210         TreeTableColumn tableColumn = (TreeTableColumn<T,?>) tcb;
 211         TreeTableCell cell = (TreeTableCell) tableColumn.getCellFactory().call(tableColumn);
 212 
 213         cell.updateTreeTableColumn(tableColumn);
 214         cell.updateTreeTableView(tableColumn.getTreeTableView());
 215 
 216         return cell;
 217     }
 218 
 219     @Override protected void updateCells(boolean resetChildren) {

 220         super.updateCells(resetChildren);
 221 
 222         if (resetChildren) {
 223             childrenDirty = true;
 224             updateChildren();
 225         }
 226     }
 227 
 228     @Override protected boolean isIndentationRequired() {

 229         return true;
 230     }
 231 
 232     @Override protected TableColumnBase getTreeColumn() {

 233         return getSkinnable().getTreeTableView().getTreeColumn();
 234     }
 235 
 236     @Override protected int getIndentationLevel(TreeTableRow<T> control) {

 237         return control.getTreeTableView().getTreeItemLevel(control.getTreeItem());
 238     }
 239 
 240     @Override protected double getIndentationPerLevel() {

 241         return getIndent();
 242     }
 243 
 244     @Override protected Node getDisclosureNode() {

 245         return getSkinnable().getDisclosureNode();
 246     }
 247 
 248     @Override protected boolean isDisclosureNodeVisible() {
 249         return getDisclosureNode() != null && treeItem != null && ! treeItem.isLeaf();
 250     }
 251 
 252     @Override protected boolean isShowRoot() {
 253         return getSkinnable().getTreeTableView().isShowRoot();
 254     }
 255 
 256     @Override protected ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {

 257         return getSkinnable().getTreeTableView().getVisibleLeafColumns();
 258     }
 259 
 260     @Override protected void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {

 261         cell.updateTreeTableRow(row);
 262     }
 263 
 264     @Override protected boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {

 265         return treeTableViewSkin == null ? false : treeTableViewSkin.isColumnPartiallyOrFullyVisible(tc);
 266     }
 267 
 268     @Override protected TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {

 269         return cell.getTableColumn();
 270     }
 271 
 272     @Override protected ObjectProperty<Node> graphicProperty() {

 273         TreeTableRow<T> treeTableRow = getSkinnable();
 274         if (treeTableRow == null) return null;
 275         if (treeItem == null) return null;
 276 
 277         return treeItem.graphicProperty();
 278     }
 279 
 280     @Override protected Control getVirtualFlowOwner() {

 281         return getSkinnable().getTreeTableView();
 282     }
 283 
 284     @Override protected DoubleProperty fixedCellSizeProperty() {

 285         return getSkinnable().getTreeTableView().fixedCellSizeProperty();
 286     }
 287 
 288 
 289 
 290     /***************************************************************************
 291      *                                                                         *
 292      * Private Implementation                                                  *
 293      *                                                                         *
 294      **************************************************************************/
 295 
 296     private void updateTreeItem() {
 297         if (treeItem != null) {
 298             treeItemListener.unregisterChangeListener(treeItem.expandedProperty());
 299             treeItemListener.unregisterChangeListener(treeItem.graphicProperty());
 300         }
 301         treeItem = getSkinnable().getTreeItem();
 302         if (treeItem != null) {
 303             treeItemListener.registerChangeListener(treeItem.graphicProperty(), "GRAPHIC");
 304         }
 305     }
 306     
 307     private void updateDisclosureNodeAndGraphic() {
 308         if (getSkinnable().isEmpty()) return;
 309         
 310         // check for graphic missing
 311         ObjectProperty<Node> graphicProperty = graphicProperty();
 312         Node newGraphic = graphicProperty == null ? null : graphicProperty.get();
 313         if (newGraphic != null) {
 314             // RT-30466: remove the old graphic
 315             if (newGraphic != graphic) {
 316                 getChildren().remove(graphic);
 317             }
 318 
 319             if (! getChildren().contains(newGraphic)) {
 320                 getChildren().add(newGraphic);
 321                 graphic = newGraphic;
 322             }
 323         }


 370                 DoubleProperty p = ((TreeTableRowSkin<?>) n.getSkin()).indentProperty();
 371                 return p == null || !p.isBound();
 372             }
 373 
 374             @Override public StyleableProperty<Number> getStyleableProperty(TreeTableRow<?> n) {
 375                 final TreeTableRowSkin<?> skin = (TreeTableRowSkin<?>) n.getSkin();
 376                 return (StyleableProperty<Number>)(WritableValue<Number>)skin.indentProperty();
 377             }
 378         };
 379         
 380         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 381         static {
 382             final List<CssMetaData<? extends Styleable, ?>> styleables =
 383                 new ArrayList<CssMetaData<? extends Styleable, ?>>(CellSkinBase.getClassCssMetaData());
 384             styleables.add(INDENT);
 385             STYLEABLES = Collections.unmodifiableList(styleables);
 386         }
 387     }
 388     
 389     /**
 390      * @return The CssMetaData associated with this class, which may include the
 391      * CssMetaData of its super classes.
 392      */
 393     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 394         return StyleableProperties.STYLEABLES;
 395     }
 396 
 397     /**
 398      * {@inheritDoc}
 399      */
 400     @Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
 401         return getClassCssMetaData();
 402     }
 403 
 404 
 405 
 406     @Override
 407     protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 408         final TreeTableView<T> treeTableView = getSkinnable().getTreeTableView();
 409         switch (attribute) {
 410             case SELECTED_ITEMS: {
 411                 // FIXME this could be optimised to iterate over cellsMap only
 412                 // (selectedCells could be big, cellsMap is much smaller)
 413                 List<Node> selection = new ArrayList<>();
 414                 int index = getSkinnable().getIndex();
 415                 for (TreeTablePosition<T,?> pos : treeTableView.getSelectionModel().getSelectedCells()) {
 416                     if (pos.getRow() == index) {
 417                         TreeTableColumn<T,?> column = pos.getTableColumn();
 418                         if (column == null) {
 419                             /* This is the row-based case */
 420                             column = treeTableView.getVisibleLeafColumn(0);
 421                         }
 422                         TreeTableCell<T,?> cell = cellsMap.get(column).get();
 423                         if (cell != null) selection.add(cell);
 424                     }
 425                     return FXCollections.observableArrayList(selection);
 426                 }
 427             }




   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 com.sun.javafx.scene.control.behavior.BehaviorBase;
  29 import javafx.beans.InvalidationListener;
  30 import javafx.collections.FXCollections;
  31 import javafx.scene.control.Control;
  32 import javafx.scene.control.TableColumnBase;
  33 import javafx.scene.control.TreeItem;
  34 import javafx.scene.control.TreeTableCell;
  35 import javafx.scene.control.TreeTableColumn;
  36 import javafx.scene.control.TreeTablePosition;
  37 import javafx.scene.control.TreeTableRow;
  38 import javafx.scene.control.TreeTableView;
  39 
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.List;
  43 
  44 import javafx.beans.property.DoubleProperty;
  45 import javafx.scene.AccessibleAttribute;
  46 import javafx.scene.Node;
  47 import javafx.css.StyleableDoubleProperty;
  48 import javafx.css.CssMetaData;
  49 
  50 import javafx.css.converter.SizeConverter;

  51 import com.sun.javafx.scene.control.behavior.TreeTableRowBehavior;
  52 
  53 import javafx.beans.property.ObjectProperty;

  54 import javafx.beans.value.WritableValue;
  55 import javafx.collections.ObservableList;
  56 import javafx.css.Styleable;
  57 import javafx.css.StyleableProperty;
  58 
  59 /**
  60  * Default skin implementation for the {@link TreeTableRow} control.
  61  *
  62  * @see TreeTableRow
  63  * @since 9
  64  */
  65 public class TreeTableRowSkin<T> extends TableRowSkinBase<TreeItem<T>, TreeTableRow<T>, TreeTableCell<T,?>> {
  66 
  67     /***************************************************************************
  68      *                                                                         *
  69      * Private Fields                                                          *
  70      *                                                                         *
  71      **************************************************************************/
  72 
  73     // maps into the TreeTableViewSkin items property via
  74     // TreeTableViewSkin.treeItemToListMap

  75     private TreeItem<?> treeItem;
  76     private boolean disclosureNodeDirty = true;
  77     private Node graphic;
  78     private final BehaviorBase<TreeTableRow<T>> behavior;
  79 
  80     private TreeTableViewSkin treeTableViewSkin;
  81 
  82     private boolean childrenDirty = false;
  83 
  84 
  85 
  86     /***************************************************************************
  87      *                                                                         *
  88      * Constructors                                                            *
  89      *                                                                         *
  90      **************************************************************************/
  91 
  92     /**
  93      * Creates a new TreeTableRowSkin instance, installing the necessary child
  94      * nodes into the Control {@link Control#getChildren() children} list, as
  95      * well as the necessary input mappings for handling key, mouse, etc events.
  96      *
  97      * @param control The control that this skin should be installed onto.
  98      */
  99     public TreeTableRowSkin(TreeTableRow<T> control) {
 100         super(control);
 101 
 102         // install default input map for the TreeTableRow control
 103         behavior = new TreeTableRowBehavior<>(control);
 104 //        control.setInputMap(behavior.getInputMap());
 105 
 106         updateTreeItem();
 107         updateTableViewSkin();
 108 
 109         registerChangeListener(control.treeTableViewProperty(), e -> updateTableViewSkin());
 110         registerChangeListener(control.indexProperty(), e -> updateCells = true);
 111         registerChangeListener(control.treeItemProperty(), e -> {
 112             updateTreeItem();
 113             isDirty = true;
 114         });
 115         registerChangeListener(control.getTreeTableView().treeColumnProperty(), e -> {
 116             // Fix for RT-27782: Need to set isDirty to true, rather than the
 117             // cheaper updateCells, as otherwise the text indentation will not
 118             // be recalculated in TreeTableCellSkin.leftLabelPadding()
 119             isDirty = true;
 120             getSkinnable().requestLayout();
 121         });
 122     }
 123 
 124 

 125     /***************************************************************************
 126      *                                                                         *
 127      * Listeners                                                               *
 128      *                                                                         *
 129      **************************************************************************/
 130 
 131     private final InvalidationListener graphicListener = o -> {

 132         disclosureNodeDirty = true;
 133         getSkinnable().requestLayout();
 134     };



 135 
 136 
 137     /***************************************************************************
 138      *                                                                         *
 139      * Properties                                                              *
 140      *                                                                         *
 141      **************************************************************************/
 142 
 143     /**
 144      * The amount of space to multiply by the treeItem.level to get the left
 145      * margin for this tree cell. This is settable from CSS
 146      */
 147     private DoubleProperty indent = null;
 148     public final void setIndent(double value) { indentProperty().set(value); }
 149     public final double getIndent() { return indent == null ? 10.0 : indent.get(); }
 150     public final DoubleProperty indentProperty() { 
 151         if (indent == null) {
 152             indent = new StyleableDoubleProperty(10.0) {
 153                 @Override public Object getBean() {
 154                     return TreeTableRowSkin.this;
 155                 }
 156 
 157                 @Override public String getName() {
 158                     return "indent";
 159                 }
 160 
 161                 @Override public CssMetaData<TreeTableRow<?>,Number> getCssMetaData() {
 162                     return TreeTableRowSkin.StyleableProperties.INDENT;
 163                 }
 164             };
 165         }
 166         return indent; 
 167     }
 168 
 169 
 170 
 171     /***************************************************************************
 172      *                                                                         *
 173      * Public API                                                              *
 174      *                                                                         *
 175      **************************************************************************/
 176 
 177     /** {@inheritDoc} */
 178     @Override public void dispose() {
 179         super.dispose();
 180 
 181         if (behavior != null) {
 182             behavior.dispose();











 183         }
 184     }
 185 
 186     /** {@inheritDoc} */
 187     @Override protected void updateChildren() {
 188         super.updateChildren();
 189 
 190         updateDisclosureNodeAndGraphic();
 191 
 192         if (childrenDirty) {
 193             childrenDirty = false;
 194             if (cells.isEmpty()) {
 195                 getChildren().clear();
 196             } else {
 197                 // TODO we can optimise this by only showing cells that are
 198                 // visible based on the table width and the amount of horizontal
 199                 // scrolling.
 200                 getChildren().addAll(cells);
 201             }
 202         }
 203     }
 204 
 205     /** {@inheritDoc} */
 206     @Override protected void layoutChildren(double x, double y, double w, double h) {
 207         if (disclosureNodeDirty) {
 208             updateDisclosureNodeAndGraphic();
 209             disclosureNodeDirty = false;
 210         }
 211 
 212         Node disclosureNode = getDisclosureNode();
 213         if (disclosureNode != null && disclosureNode.getScene() == null) {
 214             updateDisclosureNodeAndGraphic();
 215         }
 216 
 217         super.layoutChildren(x, y, w, h);
 218     }
 219 
 220 
 221 
 222     /***************************************************************************
 223      *                                                                         *
 224      * Private Implementation                                                  *
 225      *                                                                         *
 226      **************************************************************************/
 227 
 228     /** {@inheritDoc} */
 229     @Override TreeTableCell<T, ?> getCell(TableColumnBase tcb) {
 230         TreeTableColumn tableColumn = (TreeTableColumn<T,?>) tcb;
 231         TreeTableCell cell = (TreeTableCell) tableColumn.getCellFactory().call(tableColumn);
 232 
 233         cell.updateTreeTableColumn(tableColumn);
 234         cell.updateTreeTableView(tableColumn.getTreeTableView());
 235 
 236         return cell;
 237     }
 238 
 239     /** {@inheritDoc} */
 240     @Override void updateCells(boolean resetChildren) {
 241         super.updateCells(resetChildren);
 242 
 243         if (resetChildren) {
 244             childrenDirty = true;
 245             updateChildren();
 246         }
 247     }
 248 
 249     /** {@inheritDoc} */
 250     @Override boolean isIndentationRequired() {
 251         return true;
 252     }
 253 
 254     /** {@inheritDoc} */
 255     @Override TableColumnBase getTreeColumn() {
 256         return getSkinnable().getTreeTableView().getTreeColumn();
 257     }
 258 
 259     /** {@inheritDoc} */
 260     @Override int getIndentationLevel(TreeTableRow<T> control) {
 261         return control.getTreeTableView().getTreeItemLevel(control.getTreeItem());
 262     }
 263 
 264     /** {@inheritDoc} */
 265     @Override double getIndentationPerLevel() {
 266         return getIndent();
 267     }
 268 
 269     /** {@inheritDoc} */
 270     @Override Node getDisclosureNode() {
 271         return getSkinnable().getDisclosureNode();
 272     }
 273 
 274     @Override boolean isDisclosureNodeVisible() {
 275         return getDisclosureNode() != null && treeItem != null && ! treeItem.isLeaf();
 276     }
 277 
 278     @Override boolean isShowRoot() {
 279         return getSkinnable().getTreeTableView().isShowRoot();
 280     }
 281 
 282     /** {@inheritDoc} */
 283     @Override ObservableList<TreeTableColumn<T, ?>> getVisibleLeafColumns() {
 284         return getSkinnable().getTreeTableView().getVisibleLeafColumns();
 285     }
 286 
 287     /** {@inheritDoc} */
 288     @Override void updateCell(TreeTableCell<T, ?> cell, TreeTableRow<T> row) {
 289         cell.updateTreeTableRow(row);
 290     }
 291 
 292     /** {@inheritDoc} */
 293     @Override boolean isColumnPartiallyOrFullyVisible(TableColumnBase tc) {
 294         return treeTableViewSkin == null ? false : treeTableViewSkin.isColumnPartiallyOrFullyVisible(tc);
 295     }
 296 
 297     /** {@inheritDoc} */
 298     @Override TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {
 299         return cell.getTableColumn();
 300     }
 301 
 302     /** {@inheritDoc} */
 303     @Override ObjectProperty<Node> graphicProperty() {
 304         TreeTableRow<T> treeTableRow = getSkinnable();
 305         if (treeTableRow == null) return null;
 306         if (treeItem == null) return null;
 307 
 308         return treeItem.graphicProperty();
 309     }
 310 
 311     /** {@inheritDoc} */
 312     @Override Control getVirtualFlowOwner() {
 313         return getSkinnable().getTreeTableView();
 314     }
 315 
 316     /** {@inheritDoc} */
 317     @Override DoubleProperty fixedCellSizeProperty() {
 318         return getSkinnable().getTreeTableView().fixedCellSizeProperty();
 319     }
 320 








 321     private void updateTreeItem() {
 322         if (treeItem != null) {
 323             treeItem.graphicProperty().removeListener(graphicListener);

 324         }
 325         treeItem = getSkinnable().getTreeItem();
 326         if (treeItem != null) {
 327             treeItem.graphicProperty().addListener(graphicListener);
 328         }
 329     }
 330     
 331     private void updateDisclosureNodeAndGraphic() {
 332         if (getSkinnable().isEmpty()) return;
 333         
 334         // check for graphic missing
 335         ObjectProperty<Node> graphicProperty = graphicProperty();
 336         Node newGraphic = graphicProperty == null ? null : graphicProperty.get();
 337         if (newGraphic != null) {
 338             // RT-30466: remove the old graphic
 339             if (newGraphic != graphic) {
 340                 getChildren().remove(graphic);
 341             }
 342 
 343             if (! getChildren().contains(newGraphic)) {
 344                 getChildren().add(newGraphic);
 345                 graphic = newGraphic;
 346             }
 347         }


 394                 DoubleProperty p = ((TreeTableRowSkin<?>) n.getSkin()).indentProperty();
 395                 return p == null || !p.isBound();
 396             }
 397 
 398             @Override public StyleableProperty<Number> getStyleableProperty(TreeTableRow<?> n) {
 399                 final TreeTableRowSkin<?> skin = (TreeTableRowSkin<?>) n.getSkin();
 400                 return (StyleableProperty<Number>)(WritableValue<Number>)skin.indentProperty();
 401             }
 402         };
 403         
 404         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 405         static {
 406             final List<CssMetaData<? extends Styleable, ?>> styleables =
 407                 new ArrayList<CssMetaData<? extends Styleable, ?>>(CellSkinBase.getClassCssMetaData());
 408             styleables.add(INDENT);
 409             STYLEABLES = Collections.unmodifiableList(styleables);
 410         }
 411     }
 412 
 413     /**
 414      * Returns the CssMetaData associated with this class, which may include the
 415      * CssMetaData of its super classes.
 416      */
 417     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 418         return StyleableProperties.STYLEABLES;
 419     }
 420 
 421     /**
 422      * {@inheritDoc}
 423      */
 424     @Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
 425         return getClassCssMetaData();
 426     }
 427 
 428 
 429     /** {@inheritDoc} */
 430     @Override protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {

 431         final TreeTableView<T> treeTableView = getSkinnable().getTreeTableView();
 432         switch (attribute) {
 433             case SELECTED_ITEMS: {
 434                 // FIXME this could be optimised to iterate over cellsMap only
 435                 // (selectedCells could be big, cellsMap is much smaller)
 436                 List<Node> selection = new ArrayList<>();
 437                 int index = getSkinnable().getIndex();
 438                 for (TreeTablePosition<T,?> pos : treeTableView.getSelectionModel().getSelectedCells()) {
 439                     if (pos.getRow() == index) {
 440                         TreeTableColumn<T,?> column = pos.getTableColumn();
 441                         if (column == null) {
 442                             /* This is the row-based case */
 443                             column = treeTableView.getVisibleLeafColumn(0);
 444                         }
 445                         TreeTableCell<T,?> cell = cellsMap.get(column).get();
 446                         if (cell != null) selection.add(cell);
 447                     }
 448                     return FXCollections.observableArrayList(selection);
 449                 }
 450             }