javafx.scene.control.cell.CheckBoxListCell Maven / Gradle / Ivy
/*
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.control.cell;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import javafx.util.StringConverter;
/**
* A class containing a {@link ListCell} implementation that draws a
* {@link CheckBox} node inside the cell, optionally with a label to indicate
* what the checkbox represents.
*
* The CheckBoxListCell is rendered with a CheckBox on the left-hand side of
* the {@link ListView}, and the text related to the list item taking up all
* remaining horizontal space.
*
*
To construct an instance of this class, it is necessary to provide a
* {@link Callback} that, given an object of type T, will return a
* {@code ObservableValue} that represents whether the given item is
* selected or not. This ObservableValue will be bound bidirectionally (meaning
* that the CheckBox in the cell will set/unset this property based on user
* interactions, and the CheckBox will reflect the state of the
* {@code ObservableValue}, if it changes externally).
*
* Note that the CheckBoxListCell renders the CheckBox 'live', meaning that
* the CheckBox is always interactive and can be directly toggled by the user.
* This means that it is not necessary that the cell enter its
* {@link #editingProperty() editing state} (usually by the user double-clicking
* on the cell). A side-effect of this is that the usual editing callbacks
* (such as {@link javafx.scene.control.ListView#onEditCommitProperty() on edit commit})
* will not be called. If you want to be notified of changes,
* it is recommended to directly observe the boolean properties that are
* manipulated by the CheckBox.
*
* @see CheckBox
* @see ListCell
* @param The type of the elements contained within the ListView.
* @since JavaFX 2.2
*/
public class CheckBoxListCell extends ListCell {
/* *************************************************************************
* *
* Static cell factories *
* *
**************************************************************************/
/**
* Creates a cell factory for use in ListView controls. When used in a
* ListView, the {@link CheckBoxListCell} is rendered with a CheckBox on the
* left-hand side of the ListView, with the text related to the list item
* taking up all remaining horizontal space.
*
* @param The type of the elements contained within the ListView.
* @param getSelectedProperty A {@link Callback} that, given an object of
* type T (which is a value taken out of the
* {@code ListView.items} list),
* will return an {@code ObservableValue} that represents
* whether the given item is selected or not. This ObservableValue will
* be bound bidirectionally (meaning that the CheckBox in the cell will
* set/unset this property based on user interactions, and the CheckBox
* will reflect the state of the ObservableValue, if it changes
* externally).
* @return A {@link Callback} that will return a ListCell that is able to
* work on the type of element contained within the ListView items list.
*/
public static Callback, ListCell> forListView(
final Callback> getSelectedProperty) {
return forListView(getSelectedProperty, CellUtils.defaultStringConverter());
}
/**
* Creates a cell factory for use in ListView controls. When used in a
* ListView, the {@link CheckBoxListCell} is rendered with a CheckBox on the
* left-hand side of the ListView, with the text related to the list item
* taking up all remaining horizontal space.
*
* @param The type of the elements contained within the ListView.
* @param getSelectedProperty A {@link Callback} that, given an object
* of type T (which is a value taken out of the
* {@code ListView.items} list),
* will return an {@code ObservableValue} that represents
* whether the given item is selected or not. This ObservableValue will
* be bound bidirectionally (meaning that the CheckBox in the cell will
* set/unset this property based on user interactions, and the CheckBox
* will reflect the state of the ObservableValue, if it changes
* externally).
* @param converter A StringConverter that, give an object of type T, will
* return a String that can be used to represent the object visually.
* @return A {@link Callback} that will return a ListCell that is able to
* work on the type of element contained within the ListView.
*/
public static Callback, ListCell> forListView(
final Callback> getSelectedProperty,
final StringConverter converter) {
return list -> new CheckBoxListCell<>(getSelectedProperty, converter);
}
/* *************************************************************************
* *
* Fields *
* *
**************************************************************************/
private final CheckBox checkBox;
private ObservableValue booleanProperty;
/* *************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Creates a default CheckBoxListCell.
*/
public CheckBoxListCell() {
this(null);
}
/**
* Creates a default CheckBoxListCell.
*
* @param getSelectedProperty A {@link Callback} that will return an
* {@code ObservableValue} given an item from the ListView.
*/
public CheckBoxListCell(
final Callback> getSelectedProperty) {
this(getSelectedProperty, CellUtils.defaultStringConverter());
}
/**
* Creates a CheckBoxListCell with a custom string converter.
*
* @param getSelectedProperty A {@link Callback} that will return an
* {@code ObservableValue} given an item from the ListView.
* @param converter A StringConverter that, given an object of type T, will
* return a String that can be used to represent the object visually.
*/
public CheckBoxListCell(
final Callback> getSelectedProperty,
final StringConverter converter) {
this.getStyleClass().add("check-box-list-cell");
setSelectedStateCallback(getSelectedProperty);
setConverter(converter);
this.checkBox = new CheckBox();
setAlignment(Pos.CENTER_LEFT);
setContentDisplay(ContentDisplay.LEFT);
// by default the graphic is null until the cell stops being empty
setGraphic(null);
}
/* *************************************************************************
* *
* Properties *
* *
**************************************************************************/
// --- converter
private ObjectProperty> converter =
new SimpleObjectProperty<>(this, "converter");
/**
* The {@link StringConverter} property.
* @return the {@link StringConverter} property
*/
public final ObjectProperty> converterProperty() {
return converter;
}
/**
* Sets the {@link StringConverter} to be used in this cell.
* @param value the {@link StringConverter}
*/
public final void setConverter(StringConverter value) {
converterProperty().set(value);
}
/**
* Returns the {@link StringConverter} used in this cell.
* @return the {@link StringConverter} used in this cell
*/
public final StringConverter getConverter() {
return converterProperty().get();
}
// --- selected state callback property
private ObjectProperty>>
selectedStateCallback =
new SimpleObjectProperty<>(
this, "selectedStateCallback");
/**
* Property representing the {@link Callback} that is bound to by the
* CheckBox shown on screen.
* @return the {@link Callback} that is bound to by the CheckBox shown on
* screen
*/
public final ObjectProperty>> selectedStateCallbackProperty() {
return selectedStateCallback;
}
/**
* Sets the {@link Callback} that is bound to by the CheckBox shown on screen.
* @param value the {@link Callback}
*/
public final void setSelectedStateCallback(Callback> value) {
selectedStateCallbackProperty().set(value);
}
/**
* Returns the {@link Callback} that is bound to by the CheckBox shown on screen.
* @return the {@link Callback} that is bound to by the CheckBox shown on screen
*/
public final Callback> getSelectedStateCallback() {
return selectedStateCallbackProperty().get();
}
/* *************************************************************************
* *
* Public API *
* *
**************************************************************************/
/** {@inheritDoc} */
@Override public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (! empty) {
StringConverter c = getConverter();
Callback> callback = getSelectedStateCallback();
if (callback == null) {
throw new NullPointerException(
"The CheckBoxListCell selectedStateCallbackProperty can not be null");
}
setGraphic(checkBox);
setText(c != null ? c.toString(item) : (item == null ? "" : item.toString()));
if (booleanProperty != null) {
checkBox.selectedProperty().unbindBidirectional((BooleanProperty)booleanProperty);
}
booleanProperty = callback.call(item);
if (booleanProperty != null) {
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
}
} else {
setGraphic(null);
setText(null);
}
}
}