Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.control.cell; 027 028import javafx.beans.property.Property; 029import javafx.beans.property.ReadOnlyObjectWrapper; 030import javafx.beans.value.ObservableValue; 031import javafx.scene.control.TreeItem; 032import javafx.scene.control.TreeTableColumn; 033import javafx.scene.control.TreeTableColumn.CellDataFeatures; 034import javafx.util.Callback; 035import com.sun.javafx.property.PropertyReference; 036import com.sun.javafx.scene.control.Logging; 037import sun.util.logging.PlatformLogger; 038 039 040/** 041 * A convenience implementation of the Callback interface, designed specifically 042 * for use within the {@link TreeTableColumn} 043 * {@link TreeTableColumn#cellValueFactoryProperty() cell value factory}. An example 044 * of how to use this class is: 045 * 046 * <pre><code> 047 * TreeTableColumn<Person,String> firstNameCol = new TreeTableColumn<Person,String>("First Name"); 048 * firstNameCol.setCellValueFactory(new TreeItemPropertyValueFactory<Person,String>("firstName")); 049 * </code></pre> 050 * 051 * In this example, the "firstName" string is used as a reference to an assumed 052 * <code>firstNameProperty()</code> method in the <code>Person</code> class type 053 * (which is the class type of the TreeTableView). Additionally, this method must 054 * return a {@link Property} instance. If a method meeting these requirements 055 * is found, then the {@link TreeTableCell} is populated with this ObservableValue<T>. 056 * In addition, the TreeTableView will automatically add an observer to the 057 * returned value, such that any changes fired will be observed by the TreeTableView, 058 * resulting in the cell immediately updating. 059 * 060 * <p>If no method matching this pattern exists, there is fall-through support 061 * for attempting to call get<property>() or is<property>() (that is, 062 * <code>getFirstName()</code> or <code>isFirstName()</code> in the example 063 * above). If a method matching this pattern exists, the value returned from this method 064 * is wrapped in a {@link ReadOnlyObjectWrapper} and returned to the TreeTableCell. 065 * However, in this situation, this means that the TreeTableCell will not be able 066 * to observe the ObservableValue for changes (as is the case in the first 067 * approach above). 068 * 069 * <p>For reference (and as noted in the TreeTableColumn 070 * {@link TreeTableColumn#cellValueFactory cell value factory} documentation), the 071 * long form of the code above would be the following: 072 * 073 * <pre><code> 074 * TreeTableColumn<Person,String> firstNameCol = new TreeTableColumn<Person,String>("First Name"); 075 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() { 076 * public ObservableValue<String> call(CellDataFeatures<Person, String> p) { 077 * // p.getValue() returns the TreeItem<Person> instance for a particular 078 * // TreeTableView row, and the second getValue() call returns the 079 * // Person instance contained within the TreeItem. 080 * return p.getValue().getValue().firstNameProperty(); 081 * } 082 * }); 083 * } 084 * </code></pre> 085 * 086 * @see TreeTableColumn 087 * @see TreeTableView 088 * @see TreeTableCell 089 * @see PropertyValueFactory 090 * @see MapValueFactory 091 */ 092public class TreeItemPropertyValueFactory<S,T> implements Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>> { 093 094 private final String property; 095 096 private Class columnClass; 097 private String previousProperty; 098 private PropertyReference<T> propertyRef; 099 100 /** 101 * Creates a default PropertyValueFactory to extract the value from a given 102 * TableView row item reflectively, using the given property name. 103 * 104 * @param property The name of the property with which to attempt to 105 * reflectively extract a corresponding value for in a given object. 106 */ 107 public TreeItemPropertyValueFactory(String property) { 108 this.property = property; 109 } 110 111 /** {@inheritDoc} */ 112 @Override public ObservableValue<T> call(CellDataFeatures<S, T> param) { 113 TreeItem<S> treeItem = param.getValue(); 114 return getCellDataReflectively((T)treeItem.getValue()); 115 } 116 117 /** 118 * Returns the property name provided in the constructor. 119 */ 120 public final String getProperty() { return property; } 121 122 private ObservableValue<T> getCellDataReflectively(T rowData) { 123 if (getProperty() == null || getProperty().isEmpty() || rowData == null) return null; 124 125 try { 126 // we attempt to cache the property reference here, as otherwise 127 // performance suffers when working in large data models. For 128 // a bit of reference, refer to RT-13937. 129 if (columnClass == null || previousProperty == null || 130 ! columnClass.equals(rowData.getClass()) || 131 ! previousProperty.equals(getProperty())) { 132 133 // create a new PropertyReference 134 this.columnClass = rowData.getClass(); 135 this.previousProperty = getProperty(); 136 this.propertyRef = new PropertyReference<T>(rowData.getClass(), getProperty()); 137 } 138 139 return propertyRef.getProperty(rowData); 140 } catch (IllegalStateException e) { 141 try { 142 // attempt to just get the value 143 T value = propertyRef.get(rowData); 144 return new ReadOnlyObjectWrapper<T>(value); 145 } catch (IllegalStateException e2) { 146 // fall through to logged exception below 147 } 148 149 // log the warning and move on 150 final PlatformLogger logger = Logging.getControlsLogger(); 151 if (logger.isLoggable(PlatformLogger.WARNING)) { 152 logger.finest("Can not retrieve property '" + getProperty() + 153 "' in TreeItemPropertyValueFactory: " + this + 154 " with provided class type: " + rowData.getClass(), e); 155 } 156 } 157 158 return null; 159 } 160}