1 /* 2 * Copyright (c) 2012, 2013, 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.cell; 27 28 import java.util.Map; 29 30 import javafx.beans.NamedArg; 31 import javafx.beans.property.ReadOnlyBooleanWrapper; 32 import javafx.beans.property.ReadOnlyDoubleWrapper; 33 import javafx.beans.property.ReadOnlyFloatWrapper; 34 import javafx.beans.property.ReadOnlyIntegerWrapper; 35 import javafx.beans.property.ReadOnlyLongWrapper; 36 import javafx.beans.property.ReadOnlyObjectWrapper; 37 import javafx.beans.property.ReadOnlyStringWrapper; 38 import javafx.beans.value.ObservableValue; 39 import javafx.scene.control.TableCell; 40 import javafx.scene.control.TableColumn; 41 import javafx.scene.control.TableColumn.CellDataFeatures; 42 import javafx.scene.control.TableView; 43 import javafx.util.Callback; 44 45 /** 46 * A convenience implementation of the Callback interface, designed specifically 47 * for use within the {@link TableColumn} 48 * {@link TableColumn#cellValueFactoryProperty() cell value factory}. An example 49 * of how to use this class is: 50 * 51 * <pre><code> 52 * ObservableList<Map> personsMapList = ... 53 * 54 * TableColumn<Map, String> firstNameColumn = new TableColumn<Map, String>("First Name"); 55 * firstNameColumn.setCellValueFactory(new MapValueFactory<String>("firstName")); 56 * 57 * TableView<Map> table = new TableView<Map>(personMapList); 58 * tableView.getColumns().setAll(firstNameColumn); 59 * </code></pre> 60 * 61 * <p>In this example, there is a list of Map instances, where each Map instance 62 * representsa single row in the TableView. The "firstName" string is used as a 63 * key into this map, and the value corresponding to this key is returned, if 64 * one exists. If the value is an {@link ObservableValue}, then this is returned 65 * directly, otherwise the value is wrapped in a {@link ReadOnlyObjectWrapper}. 66 * 67 * @see TableColumn 68 * @see TableView 69 * @see TableCell 70 * @see PropertyValueFactory 71 * @param <T> The type of the class contained within the TableColumn cells. 72 * @since JavaFX 2.2 73 */ 74 public class MapValueFactory<T> implements Callback<CellDataFeatures<Map,T>, ObservableValue<T>> { 75 76 private final Object key; 77 78 /** 79 * Creates a default MapValueFactory, which will use the provided key to 80 * lookup the value for cells in the {@link TableColumn} in which this 81 * MapValueFactory is installed (via the 82 * {@link TableColumn#cellValueFactoryProperty() cell value factory} property. 83 * 84 * @param key The key to use to lookup the value in the {@code Map}. 85 */ 86 public MapValueFactory(final @NamedArg("key") Object key) { 87 this.key = key; 88 } 89 90 @Override public ObservableValue<T> call(CellDataFeatures<Map, T> cdf) { 91 Map map = cdf.getValue(); 92 Object value = map.get(key); 93 94 // ideally the map will contain observable values directly, and in which 95 // case we can just return this observable value. 96 if (value instanceof ObservableValue) { 97 return (ObservableValue)value; 98 } 99 100 // TODO 101 // If we are here, the value in the map for the given key is not observable, 102 // but perhaps the Map is an ObservableMap. If this is the case, we 103 // can add a listener to the map for the given key, and possibly observe 104 // it for changes and return these 105 // if (map instanceof ObservableMap) { 106 // ObservableMap oMap = (ObservableMap) map; 107 // // .... 108 // } 109 110 // Often time there is special case code to deal with specific observable 111 // value types, so we try to wrap in the most specific type. 112 if (value instanceof Boolean) { 113 return (ObservableValue<T>) new ReadOnlyBooleanWrapper((Boolean)value); 114 } else if (value instanceof Integer) { 115 return (ObservableValue<T>) new ReadOnlyIntegerWrapper((Integer)value); 116 } else if (value instanceof Float) { 117 return (ObservableValue<T>) new ReadOnlyFloatWrapper((Float)value); 118 } else if (value instanceof Long) { 119 return (ObservableValue<T>) new ReadOnlyLongWrapper((Long)value); 120 } else if (value instanceof Double) { 121 return (ObservableValue<T>) new ReadOnlyDoubleWrapper((Double)value); 122 } else if (value instanceof String) { 123 return (ObservableValue<T>) new ReadOnlyStringWrapper((String)value); 124 } 125 126 // fall back to an object wrapper 127 return new ReadOnlyObjectWrapper<T>((T)value); 128 } 129 }