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 java.util.Map;
029
030import javafx.beans.property.ReadOnlyBooleanWrapper;
031import javafx.beans.property.ReadOnlyDoubleWrapper;
032import javafx.beans.property.ReadOnlyFloatWrapper;
033import javafx.beans.property.ReadOnlyIntegerWrapper;
034import javafx.beans.property.ReadOnlyLongWrapper;
035import javafx.beans.property.ReadOnlyObjectWrapper;
036import javafx.beans.property.ReadOnlyStringWrapper;
037import javafx.beans.value.ObservableValue;
038import javafx.scene.control.TableCell;
039import javafx.scene.control.TableColumn;
040import javafx.scene.control.TableColumn.CellDataFeatures;
041import javafx.scene.control.TableView;
042import javafx.util.Callback;
043
044/**
045 * A convenience implementation of the Callback interface, designed specifically
046 * for use within the {@link TableColumn} 
047 * {@link TableColumn#cellValueFactoryProperty() cell value factory}. An example
048 * of how to use this class is:
049 * 
050 * <pre><code>
051 * ObservableList<Map> personsMapList = ...
052 * 
053 * TableColumn&lt;Map, String&gt; firstNameColumn = new TableColumn&lt;Map, String&gt;("First Name");
054 * firstNameColumn.setCellValueFactory(new MapValueFactory&lt;String&gt;("firstName"));
055 * 
056 * TableView<Map> table = new TableView<Map>(personMapList);
057 * tableView.getColumns().setAll(firstNameColumn);
058 * </code></pre>
059 * 
060 * <p>In this example, there is a list of Map instances, where each Map instance 
061 * representsa single row in the TableView. The "firstName" string is used as a 
062 * key into this map, and the value corresponding to this key is returned, if 
063 * one exists. If the value is an {@link ObservableValue}, then this is returned
064 * directly, otherwise the value is wrapped in a {@link ReadOnlyObjectWrapper}.
065 * 
066 * @see TableColumn
067 * @see TableView
068 * @see TableCell
069 * @see PropertyValueFactory
070 * @param <T> The type of the class contained within the TableColumn cells.
071 * @since 2.2
072 */
073public class MapValueFactory<T> implements Callback<CellDataFeatures<Map,T>, ObservableValue<T>> {
074
075    private final Object key;
076    
077    /**
078     * Creates a default MapValueFactory, which will use the provided key to 
079     * lookup the value for cells in the {@link TableColumn} in which this
080     * MapValueFactory is installed (via the 
081     * {@link TableColumn#cellValueFactoryProperty() cell value factory} property.
082     * 
083     * @param key The key to use to lookup the value in the {@code Map}.
084     */
085    public MapValueFactory(final Object key) {
086        this.key = key;
087    }
088    
089    @Override public ObservableValue<T> call(CellDataFeatures<Map, T> cdf) {
090        Map map = cdf.getValue();
091        Object value = map.get(key);
092        
093        // ideally the map will contain observable values directly, and in which
094        // case we can just return this observable value.
095        if (value instanceof ObservableValue) {
096            return (ObservableValue)value;
097        }
098        
099        // TODO
100        // If we are here, the value in the map for the given key is not observable,
101        // but perhaps the Map is an ObservableMap. If this is the case, we
102        // can add a listener to the map for the given key, and possibly observe
103        // it for changes and return these
104//        if (map instanceof ObservableMap) {
105//            ObservableMap oMap = (ObservableMap) map;
106//            // ....
107//        }
108        
109        // Often time there is special case code to deal with specific observable
110        // value types, so we try to wrap in the most specific type.
111        if (value instanceof Boolean) {
112            return (ObservableValue<T>) new ReadOnlyBooleanWrapper((Boolean)value);
113        } else if (value instanceof Integer) {
114            return (ObservableValue<T>) new ReadOnlyIntegerWrapper((Integer)value);
115        } else if (value instanceof Float) {
116            return (ObservableValue<T>) new ReadOnlyFloatWrapper((Float)value);
117        } else if (value instanceof Long) {
118            return (ObservableValue<T>) new ReadOnlyLongWrapper((Long)value);
119        } else if (value instanceof Double) {
120            return (ObservableValue<T>) new ReadOnlyDoubleWrapper((Double)value);
121        } else if (value instanceof String) {
122            return (ObservableValue<T>) new ReadOnlyStringWrapper((String)value);
123        }
124        
125        // fall back to an object wrapper
126        return new ReadOnlyObjectWrapper<T>((T)value);
127    }
128}