1 /* 2 * Copyright (c) 2011, 2014, 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 com.sun.javafx.scene.control.skin; 27 28 import com.sun.javafx.scene.control.behavior.CellBehaviorBase; 29 import javafx.beans.InvalidationListener; 30 import javafx.beans.WeakInvalidationListener; 31 import javafx.beans.property.BooleanProperty; 32 import javafx.beans.property.ReadOnlyDoubleProperty; 33 import javafx.scene.control.IndexedCell; 34 import javafx.scene.shape.Rectangle; 35 36 public abstract class TableCellSkinBase<C extends IndexedCell, B extends CellBehaviorBase<C>> extends CellSkinBase<C,B> { 37 38 /*************************************************************************** 39 * * 40 * Static Fields * 41 * * 42 **************************************************************************/ 43 44 // This property is set on the cell when we want to know its actual 45 // preferred width, not the width of the associated TableColumn. 46 // This is primarily used in NestedTableColumnHeader such that user double 47 // clicks result in the column being resized to fit the widest content in 48 // the column 49 static final String DEFER_TO_PARENT_PREF_WIDTH = "deferToParentPrefWidth"; 50 51 52 53 /*************************************************************************** 54 * * 55 * Private Fields * 56 * * 57 **************************************************************************/ 58 59 // Equivalent to tableColumn.widthProperty() 60 protected abstract ReadOnlyDoubleProperty columnWidthProperty(); 61 62 // Equivalent to tableColumn.visibleProperty() 63 protected abstract BooleanProperty columnVisibleProperty(); 64 65 boolean isDeferToParentForPrefWidth = false; 66 67 68 69 /*************************************************************************** 70 * * 71 * Constructors * 72 * * 73 **************************************************************************/ 74 75 public TableCellSkinBase(final C control, final B behavior) { 76 super(control, behavior); 77 78 // init(control) should not be called here - it should be called by the 79 // subclass after initialising itself. This is to prevent NPEs (for 80 // example, getVisibleLeafColumns() throws a NPE as the control itself 81 // is not yet set in subclasses). 82 } 83 84 protected void init(C control) { 85 // RT-22038 86 Rectangle clip = new Rectangle(); 87 clip.widthProperty().bind(control.widthProperty()); 88 clip.heightProperty().bind(control.heightProperty()); 89 getSkinnable().setClip(clip); 90 // --- end of RT-22038 91 92 ReadOnlyDoubleProperty columnWidthProperty = columnWidthProperty(); 93 if (columnWidthProperty != null) { 94 columnWidthProperty.addListener(weakColumnWidthListener); 95 } 96 97 registerChangeListener(control.visibleProperty(), "VISIBLE"); 98 99 if (control.getProperties().containsKey(DEFER_TO_PARENT_PREF_WIDTH)) { 100 isDeferToParentForPrefWidth = true; 101 } 102 } 103 104 105 106 /*************************************************************************** 107 * * 108 * Listeners * 109 * * 110 **************************************************************************/ 111 112 private InvalidationListener columnWidthListener = valueModel -> { 113 getSkinnable().requestLayout(); 114 }; 115 116 private WeakInvalidationListener weakColumnWidthListener = 117 new WeakInvalidationListener(columnWidthListener); 118 119 120 121 /*************************************************************************** 122 * * 123 * Public Methods * 124 * * 125 **************************************************************************/ 126 127 @Override protected void handleControlPropertyChanged(String p) { 128 super.handleControlPropertyChanged(p); 129 if ("VISIBLE".equals(p)) { 130 getSkinnable().setVisible(columnVisibleProperty().get()); 131 } 132 } 133 134 @Override public void dispose() { 135 ReadOnlyDoubleProperty columnWidthProperty = columnWidthProperty(); 136 if (columnWidthProperty != null) { 137 columnWidthProperty.removeListener(weakColumnWidthListener); 138 } 139 140 super.dispose(); 141 } 142 143 @Override protected void layoutChildren(final double x, final double y, 144 final double w, final double h) { 145 // fit the cell within this space 146 // FIXME the subtraction of bottom padding isn't right here - but it 147 // results in better visuals, so I'm leaving it in place for now. 148 layoutLabelInArea(x, y, w, h - getSkinnable().getPadding().getBottom()); 149 } 150 151 @Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { 152 if (isDeferToParentForPrefWidth) { 153 return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset); 154 } 155 return columnWidthProperty().get(); 156 } 157 }