Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2011, 2023, 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;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.function.IntPredicate;
import com.sun.javafx.logging.PlatformLogger.Level;
import com.sun.javafx.scene.control.Logging;
import com.sun.javafx.scene.control.Properties;
import com.sun.javafx.scene.control.SelectedCellsMap;
import com.sun.javafx.scene.control.behavior.TableCellBehavior;
import com.sun.javafx.scene.control.behavior.TableCellBehaviorBase;
import javafx.beans.*;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.WeakListChangeListener;
import javafx.collections.transformation.SortedList;
import javafx.css.CssMetaData;
import javafx.css.PseudoClass;
import javafx.css.Styleable;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableProperty;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
import javafx.scene.layout.Region;
import javafx.util.Callback;
import com.sun.javafx.collections.MappingChange;
import com.sun.javafx.collections.NonIterableChange;
import javafx.css.converter.SizeConverter;
import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
import com.sun.javafx.scene.control.TableColumnComparatorBase.TableColumnComparator;
import javafx.scene.control.skin.TableViewSkin;
/**
* The TableView control is designed to visualize an unlimited number of rows
* of data, broken out into columns. A TableView is therefore very similar to the
* {@link ListView} control, with the addition of support for columns. For an
* example on how to create a TableView, refer to the 'Creating a TableView'
* control section below.
*
*
The TableView control has a number of features, including:
*
*
Powerful {@link TableColumn} API:
*
*
Support for {@link TableColumn#cellFactoryProperty() cell factories} to
* easily customize {@link Cell cell} contents in both rendering and editing
* states.
*
Specification of {@link TableColumn#minWidthProperty() minWidth}/
* {@link TableColumn#prefWidthProperty() prefWidth}/
* {@link TableColumn#maxWidthProperty() maxWidth},
* and also {@link TableColumn#resizableProperty() fixed width columns}.
*
Width resizing by the user at runtime.
*
Column reordering by the user at runtime.
*
Built-in support for {@link TableColumn#getColumns() column nesting}
*
*
Different {@link #columnResizePolicyProperty() resizing policies} to
* dictate what happens when the user resizes columns.
*
Support for {@link #getSortOrder() multiple column sorting} by clicking
* the column header (hold down Shift keyboard key whilst clicking on a
* header to sort by multiple columns).
*
*
*
Note that TableView is intended to be used to visualize data - it is not
* intended to be used for laying out your user interface. If you want to lay
* your user interface out in a grid-like fashion, consider the
* {@link javafx.scene.layout.GridPane} layout instead.
*
*
Creating a TableView
*
*
* Creating a TableView is a multi-step process, and also depends on the
* underlying data model needing to be represented. For this example we'll use
* an {@literal ObservableList}, as it is the simplest way of showing data in a
* TableView. The {@code Person} class will consist of a first
* name and last name properties. That is:
*
*
{@code public class Person {
* private StringProperty firstName;
* public void setFirstName(String value) { firstNameProperty().set(value); }
* public String getFirstName() { return firstNameProperty().get(); }
* public StringProperty firstNameProperty() {
* if (firstName == null) firstName = new SimpleStringProperty(this, "firstName");
* return firstName;
* }
*
* private StringProperty lastName;
* public void setLastName(String value) { lastNameProperty().set(value); }
* public String getLastName() { return lastNameProperty().get(); }
* public StringProperty lastNameProperty() {
* if (lastName == null) lastName = new SimpleStringProperty(this, "lastName");
* return lastName;
* }
*
* public Person(String firstName, String lastName) {
* setFirstName(firstName);
* setLastName(lastName);
* }
* }}
*
*
The data we will use for this example is:
*
*
{@code List members = List.of(
* new Person("William", "Reed"),
* new Person("James", "Michaelson"),
* new Person("Julius", "Dean"));}
*
*
Firstly, we need to create a data model. As mentioned,
* for this example, we'll be using an {@literal ObservableList}:
*
*
{@code TableView table = new TableView<>();
* table.setItems(teamMembers);}
*
*
With the items set as such, TableView will automatically update whenever
* the teamMembers list changes. If the items list is available
* before the TableView is instantiated, it is possible to pass it directly into
* the constructor:
*
*
{@code TableView table = new TableView<>(teamMembers);}
*
*
At this point we now have a TableView hooked up to observe the
* teamMembers observableList. The missing ingredient
* now is the means of splitting out the data contained within the model and
* representing it in one or more {@link TableColumn TableColumn} instances. To
* create a two-column TableView to show the firstName and lastName properties,
* we extend the last code sample as follows:
*
*
With the code shown above we have fully defined the minimum properties
* required to create a TableView instance. Running this code will result in the
* TableView being
* shown with two columns for firstName and lastName. Any other properties of the
* Person class will not be shown, as no TableColumns are defined.
*
*
TableView support for classes that don't contain properties
*
*
The code shown above is the shortest possible code for creating a TableView
* when the domain objects are designed with JavaFX properties in mind
* (additionally, {@link javafx.scene.control.cell.PropertyValueFactory} supports
* normal JavaBean properties too, although there is a caveat to this, so refer
* to the class documentation for more information). When this is not the case,
* it is necessary to provide a custom cell value factory. More information
* about cell value factories can be found in the {@link TableColumn} API
* documentation, but briefly, here is how a TableColumn could be specified:
*
*
{@code firstNameCol.setCellValueFactory(new Callback, ObservableValue>() {
* public ObservableValue call(CellDataFeatures p) {
* // p.getValue() returns the Person instance for a particular TableView row
* return p.getValue().firstNameProperty();
* }
* });
*
* // or with a lambda expression:
* firstNameCol.setCellValueFactory(p -> p.getValue().firstNameProperty());}
*
*
TableView Selection / Focus APIs
*
To track selection and focus, it is necessary to become familiar with the
* {@link SelectionModel} and {@link FocusModel} classes. A TableView has at most
* one instance of each of these classes, available from
* {@link #selectionModelProperty() selectionModel} and
* {@link #focusModelProperty() focusModel} properties respectively.
* Whilst it is possible to use this API to set a new selection model, in
* most circumstances this is not necessary - the default selection and focus
* models should work in most circumstances.
*
*
The default {@link SelectionModel} used when instantiating a TableView is
* an implementation of the {@link MultipleSelectionModel} abstract class.
* However, as noted in the API documentation for
* the {@link MultipleSelectionModel#selectionModeProperty() selectionMode}
* property, the default value is {@link SelectionMode#SINGLE}. To enable
* multiple selection in a default TableView instance, it is therefore necessary
* to do the following:
*
*
The visuals of the TableView can be entirely customized by replacing the
* default {@link #rowFactoryProperty() row factory}. A row factory is used to
* generate {@link TableRow} instances, which are used to represent an entire
* row in the TableView.
*
*
In many cases, this is not what is desired however, as it is more commonly
* the case that cells be customized on a per-column basis, not a per-row basis.
* It is therefore important to note that a {@link TableRow} is not a
* {@link TableCell}. A {@link TableRow} is simply a container for zero or more
* {@link TableCell}, and in most circumstances it is more likely that you'll
* want to create custom TableCells, rather than TableRows. The primary use case
* for creating custom TableRow instances would most probably be to introduce
* some form of column spanning support.
*
*
You can create custom {@link TableCell} instances per column by assigning
* the appropriate function to the TableColumn
* {@link TableColumn#cellFactoryProperty() cell factory} property.
*
*
See the {@link Cell} class documentation for a more complete
* description of how to write custom Cells.
*
*
Sorting
*
Prior to JavaFX 8.0, the TableView control would treat the
* {@link #getItems() items} list as the view model, meaning that any changes to
* the list would be immediately reflected visually. TableView would also modify
* the order of this list directly when a user initiated a sort. This meant that
* (again, prior to JavaFX 8.0) it was not possible to have the TableView return
* to an unsorted state (after iterating through ascending and descending
* orders).
*
*
Starting with JavaFX 8.0 (and the introduction of {@link SortedList}), it
* is now possible to have the collection return to the unsorted state when
* there are no columns as part of the TableView
* {@link #getSortOrder() sort order}. To do this, you must create a SortedList
* instance, and bind its
* {@link javafx.collections.transformation.SortedList#comparatorProperty() comparator}
* property to the TableView {@link #comparatorProperty() comparator} property,
* list so:
*
*
{@code // create a SortedList based on the provided ObservableList
* SortedList sortedList = new SortedList(FXCollections.observableArrayList(2, 1, 3));
*
* // create a TableView with the sorted list set as the items it will show
* final TableView tableView = new TableView<>(sortedList);
*
* // bind the sortedList comparator to the TableView comparator
* sortedList.comparatorProperty().bind(tableView.comparatorProperty());
*
* // Don't forget to define columns!}
*
*
Editing
*
This control supports inline editing of values, and this section attempts to
* give an overview of the available APIs and how you should use them.
*
*
Firstly, cell editing most commonly requires a different user interface
* than when a cell is not being edited. This is the responsibility of the
* {@link Cell} implementation being used. For TableView, it is highly
* recommended that editing be
* {@link javafx.scene.control.TableColumn#cellFactoryProperty() per-TableColumn},
* rather than {@link #rowFactoryProperty() per row}, as more often than not
* you want users to edit each column value differently, and this approach allows
* for editors specific to each column. It is your choice whether the cell is
* permanently in an editing state (e.g. this is common for {@link CheckBox} cells),
* or to switch to a different UI when editing begins (e.g. when a double-click
* is received on a cell).
*
*
To know when editing has been requested on a cell,
* simply override the {@link javafx.scene.control.Cell#startEdit()} method, and
* update the cell {@link javafx.scene.control.Cell#textProperty() text} and
* {@link javafx.scene.control.Cell#graphicProperty() graphic} properties as
* appropriate (e.g. set the text to null and set the graphic to be a
* {@link TextField}). Additionally, you should also override
* {@link Cell#cancelEdit()} to reset the UI back to its original visual state
* when the editing concludes. In both cases it is important that you also
* ensure that you call the super method to have the cell perform all duties it
* must do to enter or exit its editing mode.
*
*
Once your cell is in an editing state, the next thing you are most probably
* interested in is how to commit or cancel the editing that is taking place. This is your
* responsibility as the cell factory provider. Your cell implementation will know
* when the editing is over, based on the user input (e.g. when the user presses
* the Enter or ESC keys on their keyboard). When this happens, it is your
* responsibility to call {@link Cell#commitEdit(Object)} or
* {@link Cell#cancelEdit()}, as appropriate.
*
*
When you call {@link Cell#commitEdit(Object)} an event is fired to the
* TableView, which you can observe by adding an {@link EventHandler} via
* {@link TableColumn#setOnEditCommit(javafx.event.EventHandler)}. Similarly,
* you can also observe edit events for
* {@link TableColumn#setOnEditStart(javafx.event.EventHandler) edit start}
* and {@link TableColumn#setOnEditCancel(javafx.event.EventHandler) edit cancel}.
*
*
By default the TableColumn edit commit handler is non-null, with a default
* handler that attempts to overwrite the property value for the
* item in the currently-being-edited row. It is able to do this as the
* {@link Cell#commitEdit(Object)} method is passed in the new value, and this
* is passed along to the edit commit handler via the
* {@link javafx.scene.control.TableColumn.CellEditEvent CellEditEvent} that is
* fired. It is simply a matter of calling
* {@link javafx.scene.control.TableColumn.CellEditEvent#getNewValue()} to
* retrieve this value.
*
*
It is very important to note that if you call
* {@link TableColumn#setOnEditCommit(javafx.event.EventHandler)} with your own
* {@link EventHandler}, then you will be removing the default handler. Unless
* you then handle the writeback to the property (or the relevant data source),
* nothing will happen. You can work around this by using the
* {@link TableColumn#addEventHandler(javafx.event.EventType, javafx.event.EventHandler)}
* method to add a {@link TableColumn#editCommitEvent()} {@link EventType} with
* your desired {@link EventHandler} as the second argument. Using this method,
* you will not replace the default implementation, but you will be notified when
* an edit commit has occurred.
*
*
Hopefully this summary answers some of the commonly asked questions.
* Fortunately, JavaFX ships with a number of pre-built cell factories that
* handle all the editing requirements on your behalf. You can find these
* pre-built cell factories in the javafx.scene.control.cell package.
*
* @see TableColumn
* @see TablePosition
* @param The type of the objects contained within the TableView items list.
* @since JavaFX 2.0
*/
@DefaultProperty("items")
public class TableView extends Control {
/* *************************************************************************
* *
* Static properties and methods *
* *
**************************************************************************/
// strings used to communicate via the TableView properties map between
// the control and the skin. Because they are private here, the strings
// are also duplicated in the TableViewSkin class - so any changes to these
// strings must also be duplicated there
static final String SET_CONTENT_WIDTH = "TableView.contentWidth";
/**
*
Very simple resize policy that just resizes the specified column by the
* provided delta and shifts all other columns (to the right of the given column)
* further to the right (when the delta is positive) or to the left (when the
* delta is negative).
*
*
It also handles the case where we have nested columns by sharing the new space,
* or subtracting the removed space, evenly between all immediate children columns.
* Of course, the immediate children may themselves be nested, and they would
* then use this policy on their children.
*/
public static final Callback UNCONSTRAINED_RESIZE_POLICY = new Callback() {
@Override public String toString() {
return "unconstrained-resize";
}
@Override public Boolean call(ResizeFeatures prop) {
double result = TableUtil.resize(prop.getColumn(), prop.getDelta());
return Double.compare(result, 0.0) == 0;
}
};
/**
*
Simple policy that ensures the width of all visible leaf columns in
* this table sum up to equal the width of the table itself.
*
*
When the user resizes a column width with this policy, the table automatically
* adjusts the width of the right hand side columns. When the user increases a
* column width, the table decreases the width of the rightmost column until it
* reaches its minimum width. Then it decreases the width of the second
* rightmost column until it reaches minimum width and so on. When all right
* hand side columns reach minimum size, the user cannot increase the size of
* resized column any more.
*/
public static final Callback CONSTRAINED_RESIZE_POLICY = new Callback() {
private boolean isFirstRun = true;
@Override public String toString() {
return "constrained-resize";
}
@Override public Boolean call(ResizeFeatures prop) {
TableView> table = prop.getTable();
List extends TableColumnBase,?>> visibleLeafColumns = table.getVisibleLeafColumns();
Boolean result = TableUtil.constrainedResize(prop,
isFirstRun,
table.contentWidth,
visibleLeafColumns);
isFirstRun = ! isFirstRun ? false : ! result;
return result;
}
};
/**
* The default {@link #sortPolicyProperty() sort policy} that this TableView
* will use if no other policy is specified. The sort policy is a simple
* {@link Callback} that accepts a TableView as the sole argument and expects
* a Boolean response representing whether the sort succeeded or not. A Boolean
* response of true represents success, and a response of false (or null) will
* be considered to represent failure.
* @since JavaFX 8.0
*/
public static final Callback DEFAULT_SORT_POLICY = new Callback() {
@Override public Boolean call(TableView table) {
try {
ObservableList> itemsList = table.getItems();
if (itemsList instanceof SortedList) {
// it is the responsibility of the SortedList to bind to the
// comparator provided by the TableView. However, we don't
// want to fail the sort (which would put the UI in an
// inconsistent state), so we return true here, but only if
// the SortedList has its comparator bound to the TableView
// comparator property.
SortedList sortedList = (SortedList) itemsList;
boolean comparatorsBound = sortedList.comparatorProperty().
isEqualTo(table.comparatorProperty()).get();
if (! comparatorsBound) {
// this isn't a good situation to be in, so lets log it
// out in case the developer is unaware
if (Logging.getControlsLogger().isLoggable(Level.INFO)) {
String s = "TableView items list is a SortedList, but the SortedList " +
"comparator should be bound to the TableView comparator for " +
"sorting to be enabled (e.g. " +
"sortedList.comparatorProperty().bind(tableView.comparatorProperty());).";
Logging.getControlsLogger().info(s);
}
}
return comparatorsBound;
} else {
if (itemsList == null || itemsList.isEmpty()) {
// sorting is not supported on null or empty lists
return true;
}
Comparator comparator = table.getComparator();
if (comparator == null) {
return true;
}
// otherwise we attempt to do a manual sort, and if successful
// we return true
FXCollections.sort(itemsList, comparator);
return true;
}
} catch (UnsupportedOperationException e) {
// TODO might need to support other exception types including:
// ClassCastException - if the class of the specified element prevents it from being added to this list
// NullPointerException - if the specified element is null and this list does not permit null elements
// IllegalArgumentException - if some property of this element prevents it from being added to this list
// If we are here the list does not support sorting, so we gracefully
// fail the sort request and ensure the UI is put back to its previous
// state. This is handled in the code that calls the sort policy.
return false;
}
}
};
/* *************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Creates a default TableView control with no content.
*
*
Refer to the {@link TableView} class documentation for details on the
* default state of other properties.
*/
public TableView() {
this(FXCollections.observableArrayList());
}
/**
* Creates a TableView with the content provided in the items ObservableList.
* This also sets up an observer such that any changes to the items list
* will be immediately reflected in the TableView itself.
*
*
Refer to the {@link TableView} class documentation for details on the
* default state of other properties.
*
* @param items The items to insert into the TableView, and the list to watch
* for changes (to automatically show in the TableView).
*/
public TableView(ObservableList items) {
getStyleClass().setAll(DEFAULT_STYLE_CLASS);
setAccessibleRole(AccessibleRole.TABLE_VIEW);
// we quite happily accept items to be null here
setItems(items);
// install default selection and focus models
// it's unlikely this will be changed by many users.
setSelectionModel(new TableViewArrayListSelectionModel(this));
setFocusModel(new TableViewFocusModel(this));
// we watch the columns list, such that when it changes we can update
// the leaf columns and visible leaf columns lists (which are read-only).
getColumns().addListener(weakColumnsObserver);
// watch for changes to the sort order list - and when it changes run
// the sort method.
getSortOrder().addListener((ListChangeListener>) c -> {
doSort(TableUtil.SortEventType.SORT_ORDER_CHANGE, c);
});
// We're watching for changes to the content width such
// that the resize policy can be run if necessary. This comes from
// TreeViewSkin.
getProperties().addListener(new MapChangeListener