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

javafx.scene.control.TableRow Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2011, 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;

import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.collections.ListChangeListener;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.control.TableView.TableViewFocusModel;

import javafx.collections.WeakListChangeListener;
import java.lang.ref.WeakReference;
import java.util.List;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.control.skin.TableRowSkin;

/**
 * 

TableRow is an {@link javafx.scene.control.IndexedCell IndexedCell}, but * rarely needs to be used by developers creating TableView instances. The only * time TableRow is likely to be encountered at all by a developer is if they * wish to create a custom {@link TableView#rowFactoryProperty() rowFactory} * that replaces an entire row of a TableView.

* *

More often than not, it is actually easier for a developer to customize * individual cells in a row, rather than the whole row itself. To do this, * you can specify a custom {@link TableColumn#cellFactoryProperty() cellFactory} * on each TableColumn instance.

* * @see TableView * @see TableColumn * @see TableCell * @see IndexedCell * @see Cell * @param The type of the item contained within the Cell. * @since JavaFX 2.0 */ public class TableRow extends IndexedCell { /* ************************************************************************* * * * Constructors * * * **************************************************************************/ /** * Constructs a default TableRow instance with a style class of 'table-row-cell' */ public TableRow() { getStyleClass().addAll(DEFAULT_STYLE_CLASS); setAccessibleRole(AccessibleRole.TABLE_ROW); } /* ************************************************************************* * * * Instance Variables * * * **************************************************************************/ /* ************************************************************************* * * * Callbacks and Events * * * **************************************************************************/ /* * This is the list observer we use to keep an eye on the SelectedIndices * list in the table view. Because it is possible that the table can * be mutated, we create this observer here, and add/remove it from the * storeTableView method. */ private ListChangeListener selectedListener = c -> { updateSelection(); }; // Same as selectedListener, but this time for focus events private final InvalidationListener focusedListener = valueModel -> { updateFocus(); }; // same as above, but for editing events private final InvalidationListener editingListener = valueModel -> { updateEditing(); }; private final WeakListChangeListener weakSelectedListener = new WeakListChangeListener<>(selectedListener); private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener); private final WeakInvalidationListener weakEditingListener = new WeakInvalidationListener(editingListener); /* ************************************************************************* * * * Properties * * * **************************************************************************/ // --- TableView private ReadOnlyObjectWrapper> tableView; private void setTableView(TableView value) { tableViewPropertyImpl().set(value); } public final TableView getTableView() { return tableView == null ? null : tableView.get(); } /** * The TableView associated with this Cell. * @return the TableView associated with this Cell */ public final ReadOnlyObjectProperty> tableViewProperty() { return tableViewPropertyImpl().getReadOnlyProperty(); } private ReadOnlyObjectWrapper> tableViewPropertyImpl() { if (tableView == null) { tableView = new ReadOnlyObjectWrapper<>() { private WeakReference> weakTableViewRef; @Override protected void invalidated() { TableView.TableViewSelectionModel sm; TableViewFocusModel fm; if (weakTableViewRef != null) { TableView oldTableView = weakTableViewRef.get(); if (oldTableView != null) { sm = oldTableView.getSelectionModel(); if (sm != null) { sm.getSelectedIndices().removeListener(weakSelectedListener); } fm = oldTableView.getFocusModel(); if (fm != null) { fm.focusedCellProperty().removeListener(weakFocusedListener); } oldTableView.editingCellProperty().removeListener(weakEditingListener); } weakTableViewRef = null; } TableView tableView = getTableView(); if (tableView != null) { sm = tableView.getSelectionModel(); if (sm != null) { sm.getSelectedIndices().addListener(weakSelectedListener); } fm = tableView.getFocusModel(); if (fm != null) { fm.focusedCellProperty().addListener(weakFocusedListener); } tableView.editingCellProperty().addListener(weakEditingListener); weakTableViewRef = new WeakReference<>(get()); } } @Override public Object getBean() { return TableRow.this; } @Override public String getName() { return "tableView"; } }; } return tableView; } /* ************************************************************************* * * * Public API * * * **************************************************************************/ /** {@inheritDoc} */ @Override protected Skin createDefaultSkin() { return new TableRowSkin<>(this); } /* ************************************************************************* * * * Private implementation * * * **************************************************************************/ /** {@inheritDoc} */ @Override void indexChanged(int oldIndex, int newIndex) { super.indexChanged(oldIndex, newIndex); updateItem(oldIndex); updateSelection(); updateFocus(); } private boolean isFirstRun = true; private void updateItem(int oldIndex) { TableView tv = getTableView(); if (tv == null || tv.getItems() == null) return; final List items = tv.getItems(); final int itemCount = items == null ? -1 : items.size(); // Compute whether the index for this cell is for a real item final int newIndex = getIndex(); boolean valid = newIndex >= 0 && newIndex < itemCount; final T oldValue = getItem(); final boolean isEmpty = isEmpty(); // Cause the cell to update itself outer: if (valid) { final T newValue = items.get(newIndex); // RT-35864 - if the index didn't change, then avoid calling updateItem // unless the item has changed. if (oldIndex == newIndex) { if (!isItemChanged(oldValue, newValue)) { // RT-37054: we break out of the if/else code here and // proceed with the code following this, so that we may // still update references, listeners, etc as required. break outer; } } updateItem(newValue, false); } else { // RT-30484 We need to allow a first run to be special-cased to allow // for the updateItem method to be called at least once to allow for // the correct visual state to be set up. In particular, in RT-30484 // refer to Ensemble8PopUpTree.png - in this case the arrows are being // shown as the new cells are instantiated with the arrows in the // children list, and are only hidden in updateItem. if ((!isEmpty && oldValue != null) || isFirstRun) { updateItem(null, true); isFirstRun = false; } } } private void updateSelection() { /* * This cell should be selected if the selection mode of the table * is row-based, and if the row that this cell represents is selected. * * If the selection mode is not row-based, then the listener in the * TableCell class might pick up the need to set a single cell to be * selected. */ if (getIndex() == -1) return; TableView table = getTableView(); boolean isSelected = table != null && table.getSelectionModel() != null && ! table.getSelectionModel().isCellSelectionEnabled() && table.getSelectionModel().isSelected(getIndex()); updateSelected(isSelected); } private void updateFocus() { if (getIndex() == -1) return; TableView table = getTableView(); if (table == null) return; TableView.TableViewSelectionModel sm = table.getSelectionModel(); TableView.TableViewFocusModel fm = table.getFocusModel(); if (sm == null || fm == null) return; boolean isFocused = ! sm.isCellSelectionEnabled() && fm.isFocused(getIndex()); setFocused(isFocused); } private void updateEditing() { if (getIndex() == -1) return; TableView table = getTableView(); if (table == null) return; TableView.TableViewSelectionModel sm = table.getSelectionModel(); if (sm == null || sm.isCellSelectionEnabled()) return; TablePosition editCell = table.getEditingCell(); if (editCell != null && editCell.getTableColumn() != null) { return; } boolean rowMatch = editCell == null ? false : editCell.getRow() == getIndex(); if (! isEditing() && rowMatch) { startEdit(); } else if (isEditing() && ! rowMatch) { cancelEdit(); } } /* ************************************************************************* * * * Expert API * * * **************************************************************************/ /** * Updates the TableView associated with this TableCell. This is typically * only done once when the TableCell is first added to the TableView. * * Note: This function is intended to be used by experts, primarily * by those implementing new Skins. It is not common * for developers or designers to access this function directly. * @param tv the TableView */ public final void updateTableView(TableView tv) { setTableView(tv); } /* ************************************************************************* * * * Stylesheet Handling * * * **************************************************************************/ private static final String DEFAULT_STYLE_CLASS = "table-row-cell"; /* ************************************************************************* * * * Accessibility handling * * * **************************************************************************/ /** {@inheritDoc} */ @Override public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { switch (attribute) { case INDEX: return getIndex(); default: return super.queryAccessibleAttribute(attribute, parameters); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy