All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datafx.control.TableViewFactory Maven / Gradle / Ivy

There is a newer version: 8.0b1
Show newest version
/**
 * Copyright (c) 2011, 2013, Jonathan Giles, Johan Vos, Hendrik Ebbers
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *     * Neither the name of DataFX, the website javafxdata.org, nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.datafx.control;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.ChoiceBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;

/**
 * A convenience class intended to make creating a TableView easier. In
 * particular, this class can create a TableView, as well as default TableColumn
 * instances which are preconfigured with {@link TableColumn#cellValueFactoryProperty() cell
 * value factories} that are able to extract the relevant data from a given
 * Class type.
 *
 * 

In addition to this, the TableViewFactory is able to refine the * automatically generated TableColumns by reducing the columns added to the * TableView, as well as renaming and reordering. * *

An example of using this API to create a TableView is shown below: * *

 * 
 * TableView tableView = TableViewFactory.
 *     create(Person.class, personsList).
 *     selectColumns("First Name", "Last Name", "Telecommuter", "Employee Type", "Balance", "Earnings").
 *     renameColumn("Employee Type", "Type").
 *     renameColumn("Telecommuter", "Remote").
 *     buildTableView();
 * 
 * 
* * @author Jonathan Giles */ public class TableViewFactory { private TableViewFactory() { } public static TableView create(Class dataType) { List> columns = createColumns(dataType); TableView table = new TableView(); table.getColumns().setAll(columns); return table; } public static TableViewFactory create(List items) { return create(FXCollections.observableArrayList(items)); } public static TableViewFactory create(Class dataType, List items) { return create(dataType, FXCollections.observableArrayList(items)); } public static TableViewFactory create(ObservableList items) { return create(null, FXCollections.observableArrayList(items)); } public static TableViewFactory create(Class dataType, final ObservableList items) { if (items == null) { throw new NullPointerException("items can not be null"); } final TableView table = new TableView(); table.setItems(items); table.setEditable(true); if (dataType == null && table.getItems().isEmpty()) { // we'll have to create the columns the first time the items list // changes, so let's hook in a listener InvalidationListener listener = new InvalidationListener() { @Override public void invalidated(Observable o) { if (!table.getItems().isEmpty()) { createColumns(table); // remove listener items.removeListener(this); } } }; table.getItems().addListener(listener); } else { createColumns(table); } return TableViewFactory.configure(table); } private static void createColumns(TableView table) { @SuppressWarnings("unchecked") Class actualDataType = (Class)table.getItems().get(0).getClass(); if (actualDataType != null) { List> columns = createColumns(actualDataType); table.getColumns().setAll(columns); } } private static List> createColumns(Class dataType) { List> columns = new ArrayList>(); try { // TODO inspect the class, create columns for all public properties BeanInfo beanInfo = Introspector.getBeanInfo(dataType); PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors(); for (int i = 0; i < properties.length; i++) { PropertyDescriptor pd = properties[i]; if ("class".equals(pd.getName())) { continue; } if (pd.getReadMethod() == null) { continue; } Class propertyDataType = pd.getPropertyType(); // System.out.println("Name: " + pd.getName() + ", class: " + propertyDataType); String displayName = makePrettyDisplayName(pd.getDisplayName()); TableColumn column = new TableColumn(); column.setText(displayName); column.setCellValueFactory(new PropertyValueFactory(pd.getName())); columns.add(column); // TODO set property name in the TableColumn properties map // install custom cell factory if (propertyDataType.isEnum()) { Object[] enumConstants = propertyDataType.getEnumConstants(); column.setCellFactory(ChoiceBoxTableCell.forTableColumn(enumConstants)); } else if (propertyDataType == boolean.class) { column.setCellFactory(CheckBoxTableCell.forTableColumn(column)); } else if (propertyDataType == String.class) { column.setCellFactory(TextFieldTableCell.forTableColumn()); } } } catch (IntrospectionException ex) { ex.printStackTrace(); } return columns; } private static String makePrettyDisplayName(String name) { // split at each capital letter if (name == null || name.length() == 0) { return name; } if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) { return name; } char chars[] = name.toCharArray(); List charList = new ArrayList(chars.length); for (int i = 0; i < chars.length; i++) { char c0 = chars[i]; char c1 = i > 0 ? chars[i - 1] : ' '; if (i == 0) { charList.add(Character.toUpperCase(c0)); continue; } if (Character.isUpperCase(c0) && !Character.isUpperCase(c1)) { // insert space charList.add(' '); } charList.add(c0); } chars = new char[charList.size()]; for (int i = 0; i < charList.size(); i++) { chars[i] = charList.get(i); } return new String(chars); } private TableView table; private ObservableList> columns; private boolean columnSelectPerformed = false; private ObservableList> finalColumns; public static TableViewFactory configure(TableView table) { return new TableViewFactory(table); } public static void print(TableView table) { print(table.getColumns()); } public static void print(ObservableList> columns) { System.out.println("Columns:"); for (int i = 0; i < columns.size(); i++) { TableColumn tc = columns.get(i); System.out.println(" Text: " + tc.getText()); } } private TableViewFactory(TableView table/*, ObservableList columns*/) { this.table = table; this.columns = table.getColumns(); //columns == null ? table.getColumns() : columns; this.finalColumns = FXCollections.observableArrayList(); if (this.columns == null) { throw new NullPointerException("Columns can not be null"); } } public TableViewFactory selectColumns(String... names) { if (names == null || names.length == 0) { return this; } TableColumn tc; for (int i = 0; i < names.length; i++) { String name = names[i]; for (int j = 0; j < columns.size(); j++) { tc = columns.get(j); if (name == null) continue; if (name.equals(tc.getText())) { finalColumns.add(tc); columnSelectPerformed = true; } } } return this; } public TableViewFactory renameColumn(String oldName, String newName) { if (oldName == null || oldName.isEmpty() || newName == null || newName.isEmpty()) { return this; } for (int i = 0; i < columns.size(); i++) { TableColumn tc = columns.get(i); if (oldName.equals(tc.getText())) { tc.setText(newName); break; } } return this; } public ObservableList> buildColumns() { return finalColumns; } public TableView buildTableView() { if (table == null) { table = new TableView(); } if (columnSelectPerformed) { table.getColumns().setAll(finalColumns); } else if (!table.getColumns().equals(columns)) { table.getColumns().setAll(columns); } return table; } // public ObservableList> buildAndSetInTableView() { // if (table == null) { // throw new IllegalStateException("Can not set columns in TableView, as TableView instance is null"); // } // table.getColumns().setAll(finalColumns); // return finalColumns; // } }