Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 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.TableCell; 032import javafx.scene.control.TableColumn; 033import javafx.scene.control.TableColumn.CellDataFeatures; 034import javafx.scene.control.TableView; 035import javafx.util.Callback; 036 037import sun.util.logging.PlatformLogger; 038import com.sun.javafx.property.PropertyReference; 039import com.sun.javafx.scene.control.Logging; 040 041 042/** 043 * A convenience implementation of the Callback interface, designed specifically 044 * for use within the {@link TableColumn} 045 * {@link TableColumn#cellValueFactoryProperty() cell value factory}. An example 046 * of how to use this class is: 047 * 048 * <pre><code> 049 * TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); 050 * firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName")); 051 * </code></pre> 052 * 053 * In this example, the "firstName" string is used as a reference to an assumed 054 * <code>firstNameProperty()</code> method in the <code>Person</code> class type 055 * (which is the class type of the TableView 056 * {@link TableView#itemsProperty() items} list). Additionally, this method must 057 * return a {@link Property} instance. If a method meeting these requirements 058 * is found, then the {@link TableCell} is populated with this ObservableValue<T>. 059 * In addition, the TableView will automatically add an observer to the 060 * returned value, such that any changes fired will be observed by the TableView, 061 * resulting in the cell immediately updating. 062 * 063 * <p>If no method matching this pattern exists, there is fall-through support 064 * for attempting to call get<property>() or is<property>() (that is, 065 * <code>getFirstName()</code> or <code>isFirstName()</code> in the example 066 * above). If a method matching this pattern exists, the value returned from this method 067 * is wrapped in a {@link ReadOnlyObjectWrapper} and returned to the TableCell. 068 * However, in this situation, this means that the TableCell will not be able 069 * to observe the ObservableValue for changes (as is the case in the first 070 * approach above). 071 * 072 * <p>For reference (and as noted in the TableColumn 073 * {@link TableColumn#cellValueFactory cell value factory} documentation), the 074 * long form of the code above would be the following: 075 * 076 * <pre><code> 077 * TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); 078 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() { 079 * public ObservableValue<String> call(CellDataFeatures<Person, String> p) { 080 * // p.getValue() returns the Person instance for a particular TableView row 081 * return p.getValue().firstNameProperty(); 082 * } 083 * }); 084 * } 085 * </code></pre> 086 * 087 * @see TableColumn 088 * @see TableView 089 * @see TableCell 090 * @see TreeItemPropertyValueFactory 091 * @see MapValueFactory 092 * @param <S> The type of the class contained within the TableView.items list. 093 * @param <T> The type of the class contained within the TableColumn cells. 094 */ 095public class PropertyValueFactory<S,T> implements Callback<CellDataFeatures<S,T>, ObservableValue<T>> { 096 097 private final String property; 098 099 private Class columnClass; 100 private String previousProperty; 101 private PropertyReference<T> propertyRef; 102 103 /** 104 * Creates a default PropertyValueFactory to extract the value from a given 105 * TableView row item reflectively, using the given property name. 106 * 107 * @param property The name of the property with which to attempt to 108 * reflectively extract a corresponding value for in a given object. 109 */ 110 public PropertyValueFactory(String property) { 111 this.property = property; 112 } 113 114 /** {@inheritDoc} */ 115 @Override public ObservableValue<T> call(CellDataFeatures<S,T> param) { 116 return getCellDataReflectively((T)param.getValue()); 117 } 118 119 /** 120 * Returns the property name provided in the constructor. 121 */ 122 public final String getProperty() { return property; } 123 124 private ObservableValue<T> getCellDataReflectively(T rowData) { 125 if (getProperty() == null || getProperty().isEmpty() || rowData == null) return null; 126 127 try { 128 // we attempt to cache the property reference here, as otherwise 129 // performance suffers when working in large data models. For 130 // a bit of reference, refer to RT-13937. 131 if (columnClass == null || previousProperty == null || 132 ! columnClass.equals(rowData.getClass()) || 133 ! previousProperty.equals(getProperty())) { 134 135 // create a new PropertyReference 136 this.columnClass = rowData.getClass(); 137 this.previousProperty = getProperty(); 138 this.propertyRef = new PropertyReference<T>(rowData.getClass(), getProperty()); 139 } 140 141 return propertyRef.getProperty(rowData); 142 } catch (IllegalStateException e) { 143 try { 144 // attempt to just get the value 145 T value = propertyRef.get(rowData); 146 return new ReadOnlyObjectWrapper<T>(value); 147 } catch (IllegalStateException e2) { 148 // fall through to logged exception below 149 } 150 151 // log the warning and move on 152 final PlatformLogger logger = Logging.getControlsLogger(); 153 if (logger.isLoggable(PlatformLogger.WARNING)) { 154 logger.finest("Can not retrieve property '" + getProperty() + 155 "' in PropertyValueFactory: " + this + 156 " with provided class type: " + rowData.getClass(), e); 157 } 158 } 159 160 return null; 161 } 162}