/*
 * Copyright (c) 2010, 2017, 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.css.PseudoClass;
import javafx.scene.control.skin.TreeTableCellSkin;
import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.event.Event;

import javafx.collections.WeakListChangeListener;
import java.lang.ref.WeakReference;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;

import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.control.TreeTableColumn.CellEditEvent;
import javafx.scene.control.TreeTableView.TreeTableViewFocusModel;


Represents a single row/column intersection in a TreeTableView. To represent this intersection, a TreeTableCell contains an index property, as well as a tableColumn property. In addition, a TreeTableCell instance knows what TreeTableRow it exists in.

A note about selection: A TreeTableCell visually shows it is selected when two conditions are met:

  1. The TableSelectionModel.isSelected(int, TableColumnBase) method returns true for the row / column that this cell represents, and
  2. The cell selection mode property is set to true (to represent that it is allowable to select individual cells (and not just rows of cells)).
Type parameters:
  • <S> – The type of the TreeTableView generic type
  • <T> – The type of the item contained within the Cell.
See Also:
Since:JavaFX 8.0
/** * Represents a single row/column intersection in a {@link TreeTableView}. To * represent this intersection, a TreeTableCell contains an * {@link #indexProperty() index} property, as well as a * {@link #tableColumnProperty() tableColumn} property. In addition, a TreeTableCell * instance knows what {@link TreeTableRow} it exists in. * * <p><strong>A note about selection:</strong> A TreeTableCell visually shows it is * selected when two conditions are met: * <ol> * <li>The {@link TableSelectionModel#isSelected(int, TableColumnBase)} method * returns true for the row / column that this cell represents, and</li> * <li>The {@link javafx.scene.control.TableSelectionModel#cellSelectionEnabledProperty() cell selection mode} * property is set to true (to represent that it is allowable to select * individual cells (and not just rows of cells)).</li> * </ol> * * @param <S> The type of the TreeTableView generic type * @see TreeTableView * @see TreeTableColumn * @see Cell * @see IndexedCell * @see TreeTableRow * @param <T> The type of the item contained within the Cell. * @since JavaFX 8.0 */
public class TreeTableCell<S,T> extends IndexedCell<T> { /*************************************************************************** * * * Constructors * * * **************************************************************************/
Constructs a default TreeTableCell instance with a style class of 'tree-table-cell'.
/** * Constructs a default TreeTableCell instance with a style class of * 'tree-table-cell'. */
public TreeTableCell() { getStyleClass().addAll(DEFAULT_STYLE_CLASS); setAccessibleRole(AccessibleRole.TREE_TABLE_CELL); updateColumnIndex(); }
* Private fields * *
/*************************************************************************** * * * Private fields * * * **************************************************************************/
// package for testing boolean lockItemOnEdit = false;
* Callbacks and Events * *
/*************************************************************************** * * * Callbacks and Events * * * **************************************************************************/
private boolean itemDirty = false; /* * This is the list observer we use to keep an eye on the SelectedCells * ObservableList in the tree 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<TreeTablePosition<S,?>> selectedListener = c -> { while (c.next()) { if (c.wasAdded() || c.wasRemoved()) { updateSelection(); } } }; // same as above, but for focus private final InvalidationListener focusedListener = value -> { updateFocus(); }; // same as above, but for for changes to the properties on TableRow private final InvalidationListener tableRowUpdateObserver = value -> { itemDirty = true; requestLayout(); }; private final InvalidationListener editingListener = value -> { updateEditing(); }; private ListChangeListener<TreeTableColumn<S,?>> visibleLeafColumnsListener = c -> { updateColumnIndex(); }; private ListChangeListener<String> columnStyleClassListener = c -> { while (c.next()) { if (c.wasRemoved()) { getStyleClass().removeAll(c.getRemoved()); } if (c.wasAdded()) { getStyleClass().addAll(c.getAddedSubList()); } } }; private final InvalidationListener rootPropertyListener = observable -> { updateItem(-1); }; private final InvalidationListener columnStyleListener = value -> { if (getTableColumn() != null) { possiblySetStyle(getTableColumn().getStyle()); } }; private final InvalidationListener columnIdListener = value -> { if (getTableColumn() != null) { possiblySetId(getTableColumn().getId()); } }; private final WeakListChangeListener<TreeTablePosition<S,?>> weakSelectedListener = new WeakListChangeListener<TreeTablePosition<S,?>>(selectedListener); private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener); private final WeakInvalidationListener weaktableRowUpdateObserver = new WeakInvalidationListener(tableRowUpdateObserver); private final WeakInvalidationListener weakEditingListener = new WeakInvalidationListener(editingListener); private final WeakListChangeListener<TreeTableColumn<S,?>> weakVisibleLeafColumnsListener = new WeakListChangeListener<TreeTableColumn<S,?>>(visibleLeafColumnsListener); private final WeakListChangeListener<String> weakColumnStyleClassListener = new WeakListChangeListener<String>(columnStyleClassListener); private final WeakInvalidationListener weakColumnStyleListener = new WeakInvalidationListener(columnStyleListener); private final WeakInvalidationListener weakColumnIdListener = new WeakInvalidationListener(columnIdListener); private final WeakInvalidationListener weakRootPropertyListener = new WeakInvalidationListener(rootPropertyListener); /*************************************************************************** * * * Properties * * * **************************************************************************/ // --- TableColumn
The TreeTableColumn instance that backs this TreeTableCell.
/** * The TreeTableColumn instance that backs this TreeTableCell. */
private ReadOnlyObjectWrapper<TreeTableColumn<S,T>> treeTableColumn = new ReadOnlyObjectWrapper<TreeTableColumn<S,T>>(this, "treeTableColumn") { @Override protected void invalidated() { updateColumnIndex(); } }; public final ReadOnlyObjectProperty<TreeTableColumn<S,T>> tableColumnProperty() { return treeTableColumn.getReadOnlyProperty(); } private void setTableColumn(TreeTableColumn<S,T> value) { treeTableColumn.set(value); } public final TreeTableColumn<S,T> getTableColumn() { return treeTableColumn.get(); } // --- TableView
The TreeTableView associated with this TreeTableCell.
/** * The TreeTableView associated with this TreeTableCell. */
private ReadOnlyObjectWrapper<TreeTableView<S>> treeTableView; private void setTreeTableView(TreeTableView<S> value) { treeTableViewPropertyImpl().set(value); } public final TreeTableView<S> getTreeTableView() { return treeTableView == null ? null : treeTableView.get(); } public final ReadOnlyObjectProperty<TreeTableView<S>> treeTableViewProperty() { return treeTableViewPropertyImpl().getReadOnlyProperty(); } private ReadOnlyObjectWrapper<TreeTableView<S>> treeTableViewPropertyImpl() { if (treeTableView == null) { treeTableView = new ReadOnlyObjectWrapper<TreeTableView<S>>(this, "treeTableView") { private WeakReference<TreeTableView<S>> weakTableViewRef; @Override protected void invalidated() { TreeTableView.TreeTableViewSelectionModel<S> sm; TreeTableView.TreeTableViewFocusModel<S> fm; if (weakTableViewRef != null) { TreeTableView<S> oldTableView = weakTableViewRef.get(); if (oldTableView != null) { sm = oldTableView.getSelectionModel(); if (sm != null) { sm.getSelectedCells().removeListener(weakSelectedListener); } fm = oldTableView.getFocusModel(); if (fm != null) { fm.focusedCellProperty().removeListener(weakFocusedListener); } oldTableView.editingCellProperty().removeListener(weakEditingListener); oldTableView.getVisibleLeafColumns().removeListener(weakVisibleLeafColumnsListener); oldTableView.rootProperty().removeListener(weakRootPropertyListener); } } TreeTableView<S> newTreeTableView = get(); if (newTreeTableView != null) { sm = newTreeTableView.getSelectionModel(); if (sm != null) { sm.getSelectedCells().addListener(weakSelectedListener); } fm = newTreeTableView.getFocusModel(); if (fm != null) { fm.focusedCellProperty().addListener(weakFocusedListener); } newTreeTableView.editingCellProperty().addListener(weakEditingListener); newTreeTableView.getVisibleLeafColumns().addListener(weakVisibleLeafColumnsListener); newTreeTableView.rootProperty().addListener(weakRootPropertyListener); weakTableViewRef = new WeakReference<TreeTableView<S>>(newTreeTableView); } updateColumnIndex(); } }; } return treeTableView; } // --- TableRow
The TreeTableRow that this TreeTableCell currently finds itself placed within.
/** * The TreeTableRow that this TreeTableCell currently finds itself placed within. */
private ReadOnlyObjectWrapper<TreeTableRow<S>> treeTableRow = new ReadOnlyObjectWrapper<TreeTableRow<S>>(this, "treeTableRow"); private void setTreeTableRow(TreeTableRow<S> value) { treeTableRow.set(value); } public final TreeTableRow<S> getTreeTableRow() { return treeTableRow.get(); } public final ReadOnlyObjectProperty<TreeTableRow<S>> tableRowProperty() { return treeTableRow; } /*************************************************************************** * * * Editing API * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override public void startEdit() { if (isEditing()) return; final TreeTableView<S> table = getTreeTableView(); final TreeTableColumn<S,T> column = getTableColumn(); if (! isEditable() || (table != null && ! table.isEditable()) || (column != null && ! getTableColumn().isEditable())) { return; } // We check the boolean lockItemOnEdit field here, as whilst we want to // updateItem normally, when it comes to unit tests we can't have the // item change in all circumstances. if (! lockItemOnEdit) { updateItem(-1); } // it makes sense to get the cell into its editing state before firing // the event to listeners below, so that's what we're doing here // by calling super.startEdit(). super.startEdit(); if (column != null) { CellEditEvent editEvent = new CellEditEvent( table, table.getEditingCell(), TreeTableColumn.<S,T>editStartEvent(), null ); Event.fireEvent(column, editEvent); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void commitEdit(T newValue) { if (! isEditing()) return; final TreeTableView<S> table = getTreeTableView(); if (table != null) { @SuppressWarnings("unchecked") TreeTablePosition<S,T> editingCell = (TreeTablePosition<S,T>) table.getEditingCell(); // Inform the TableView of the edit being ready to be committed. CellEditEvent<S,T> editEvent = new CellEditEvent<S,T>( table, editingCell, TreeTableColumn.<S,T>editCommitEvent(), newValue ); Event.fireEvent(getTableColumn(), editEvent); } // inform parent classes of the commit, so that they can switch us // out of the editing state. // This MUST come before the updateItem call below, otherwise it will // call cancelEdit(), resulting in both commit and cancel events being // fired (as identified in RT-29650) super.commitEdit(newValue); // update the item within this cell, so that it represents the new value updateItem(newValue, false); if (table != null) { // reset the editing cell on the TableView table.edit(-1, null); // request focus back onto the table, only if the current focus // owner has the table as a parent (otherwise the user might have // clicked out of the table entirely and given focus to something else. // It would be rude of us to request it back again. ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(table); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void cancelEdit() { if (! isEditing()) return; final TreeTableView<S> table = getTreeTableView(); super.cancelEdit(); // reset the editing index on the TableView if (table != null) { @SuppressWarnings("unchecked") TreeTablePosition<S,T> editingCell = (TreeTablePosition<S,T>) table.getEditingCell(); if (updateEditingIndex) table.edit(-1, null); // request focus back onto the table, only if the current focus // owner has the table as a parent (otherwise the user might have // clicked out of the table entirely and given focus to something else. // It would be rude of us to request it back again. ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(table); CellEditEvent<S,T> editEvent = new CellEditEvent<S,T>( table, editingCell, TreeTableColumn.<S,T>editCancelEvent(), null ); Event.fireEvent(getTableColumn(), editEvent); } } /* ************************************************************************* * * * Overriding methods * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override public void updateSelected(boolean selected) { // copied from Cell, with the first conditional clause below commented // out, as it is valid for an empty TableCell to be selected, as long // as the parent TableRow is not empty (see RT-15529). /*if (selected && isEmpty()) return;*/ if (getTreeTableRow() == null || getTreeTableRow().isEmpty()) return; setSelected(selected); } /* ************************************************************************* * * * Private Implementation * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override void indexChanged(int oldIndex, int newIndex) { super.indexChanged(oldIndex, newIndex); if (isEditing() && newIndex == oldIndex) { // no-op // Fix for RT-31165 - if we (needlessly) update the index whilst the // cell is being edited it will no longer be in an editing state. // This means that in certain (common) circumstances that it will // appear that a cell is uneditable as, despite being clicked, it // will not change to the editing state as a layout of VirtualFlow // is immediately invoked, which forces all cells to be updated. } else { // Ideally we would just use the following two lines of code, rather // than the updateItem() call beneath, but if we do this we end up with // RT-22428 where all the columns are collapsed. // itemDirty = true; // requestLayout(); updateItem(oldIndex); updateSelection(); updateFocus(); updateEditing(); } } private boolean isLastVisibleColumn = false; private int columnIndex = -1; private void updateColumnIndex() { final TreeTableView<S> tv = getTreeTableView(); TreeTableColumn<S,T> tc = getTableColumn(); columnIndex = tv == null || tc == null ? -1 : tv.getVisibleLeafIndex(tc); // update the pseudo class state regarding whether this is the last // visible cell (i.e. the right-most). isLastVisibleColumn = getTableColumn() != null && columnIndex != -1 && columnIndex == tv.getVisibleLeafColumns().size() - 1; pseudoClassStateChanged(PSEUDO_CLASS_LAST_VISIBLE, isLastVisibleColumn); } private void updateSelection() { /* * This cell should be selected if the selection mode of the table * is cell-based, and if the row and column that this cell represents * is selected. * * If the selection mode is not cell-based, then the listener in the * TableRow class might pick up the need to set an entire row to be * selected. */ if (isEmpty()) return; final boolean isSelected = isSelected(); if (! isInCellSelectionMode()) { if (isSelected) { updateSelected(false); } return; } final TreeTableView<S> tv = getTreeTableView(); if (getIndex() == -1 || tv == null) return; TreeTableView.TreeTableViewSelectionModel<S> sm = tv.getSelectionModel(); if (sm == null) { updateSelected(false); return; } boolean isSelectedNow = sm.isSelected(getIndex(), getTableColumn()); if (isSelected == isSelectedNow) return; updateSelected(isSelectedNow); } private void updateFocus() { final boolean isFocused = isFocused(); if (! isInCellSelectionMode()) { if (isFocused) { setFocused(false); } return; } final TreeTableView<S> tv = getTreeTableView(); if (getIndex() == -1 || tv == null) return; TreeTableView.TreeTableViewFocusModel<S> fm = tv.getFocusModel(); if (fm == null) { setFocused(false); return; } setFocused(fm.isFocused(getIndex(), getTableColumn())); } private void updateEditing() { final TreeTableView<S> tv = getTreeTableView(); if (getIndex() == -1 || tv == null) return; TreeTablePosition<S,?> editCell = tv.getEditingCell(); boolean match = match(editCell); if (match && ! isEditing()) { startEdit(); } else if (! match && isEditing()) { // If my index is not the one being edited then I need to cancel // the edit. The tricky thing here is that as part of this call // I cannot end up calling list.edit(-1) the way that the standard // cancelEdit method would do. Yet, I need to call cancelEdit // so that subclasses which override cancelEdit can execute. So, // I have to use a kind of hacky flag workaround. updateEditingIndex = false; cancelEdit(); updateEditingIndex = true; } } private boolean updateEditingIndex = true; private boolean match(TreeTablePosition pos) { return pos != null && pos.getRow() == getIndex() && pos.getTableColumn() == getTableColumn(); } private boolean isInCellSelectionMode() { TreeTableView<S> tv = getTreeTableView(); if (tv == null) return false; TreeTableView.TreeTableViewSelectionModel<S> sm = tv.getSelectionModel(); return sm != null && sm.isCellSelectionEnabled(); } /* * This was brought in to fix the issue in RT-22077, namely that the * ObservableValue was being GC'd, meaning that changes to the value were * no longer being delivered. By extracting this value out of the method, * it is now referred to from TableCell and will therefore no longer be * GC'd. */ private ObservableValue<T> currentObservableValue = null; private boolean isFirstRun = true; private WeakReference<S> oldRowItemRef; /* * This is called when we think that the data within this TreeTableCell may have * changed. You'll note that this is a private function - it is only called * when one of the triggers above call it. */ private void updateItem(int oldIndex) { if (currentObservableValue != null) { currentObservableValue.removeListener(weaktableRowUpdateObserver); } // get the total number of items in the data model final TreeTableView<S> tableView = getTreeTableView(); final TreeTableColumn<S,T> tableColumn = getTableColumn(); final int itemCount = tableView == null ? -1 : getTreeTableView().getExpandedItemCount(); final int index = getIndex(); final boolean isEmpty = isEmpty(); final T oldValue = getItem(); final TreeTableRow<S> tableRow = getTreeTableRow(); final S rowItem = tableRow == null ? null : tableRow.getItem(); final boolean indexExceedsItemCount = index >= itemCount; // there is a whole heap of reasons why we should just punt... outer: if (indexExceedsItemCount || index < 0 || columnIndex < 0 || !isVisible() || tableColumn == null || !tableColumn.isVisible() || tableView.getRoot() == null) { // 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. // RT-32621: There are circumstances where we need to updateItem, // even when the index is greater than the itemCount. For example, // RT-32621 identifies issues where a TreeTableView collapses a // TreeItem but the custom cells remain visible. This is now // resolved with the check for indexExceedsItemCount. if ((!isEmpty && oldValue != null) || isFirstRun || indexExceedsItemCount) { updateItem(null, true); isFirstRun = false; } return; } else { currentObservableValue = tableColumn.getCellObservableValue(index); final T newValue = currentObservableValue == null ? null : currentObservableValue.getValue(); // RT-35864 - if the index didn't change, then avoid calling updateItem // unless the item has changed. if (oldIndex == index) { if (!isItemChanged(oldValue, newValue)) { // RT-36670: we need to check the row item here to prevent // the issue where the cell value and index doesn't change, // but the backing row object does. S oldRowItem = oldRowItemRef != null ? oldRowItemRef.get() : null; if (oldRowItem != null && oldRowItem.equals(rowItem)) { // 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); } oldRowItemRef = new WeakReference<>(rowItem); if (currentObservableValue == null) { return; } // add property change listeners to this item currentObservableValue.addListener(weaktableRowUpdateObserver); } @Override protected void layoutChildren() { if (itemDirty) { updateItem(-1); itemDirty = false; } super.layoutChildren(); } /*************************************************************************** * * * Expert API * * * **************************************************************************/
Updates the TreeTableView associated with this TreeTableCell. This is typically only done once when the TreeTableCell is first added to the TreeTableView. 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.
Params:
  • tv – the TreeTableView associated with this TreeTableCell
/** * Updates the TreeTableView associated with this TreeTableCell. This is typically * only done once when the TreeTableCell is first added to the TreeTableView. * * 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 TreeTableView associated with this TreeTableCell */
public final void updateTreeTableView(TreeTableView<S> tv) { setTreeTableView(tv); }
Updates the TreeTableRow associated with this TreeTableCell. 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.
Params:
  • treeTableRow – the TreeTableRow associated with this TreeTableCell
/** * Updates the TreeTableRow associated with this TreeTableCell. * * 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 treeTableRow the TreeTableRow associated with this TreeTableCell */
public final void updateTreeTableRow(TreeTableRow<S> treeTableRow) { this.setTreeTableRow(treeTableRow); }
Updates the TreeTableColumn associated with this TreeTableCell. 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.
Params:
  • col – the TreeTableColumn associated with this TreeTableCell
/** * Updates the TreeTableColumn associated with this TreeTableCell. * * 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 col the TreeTableColumn associated with this TreeTableCell */
public final void updateTreeTableColumn(TreeTableColumn<S,T> col) { // remove style class of existing tree table column, if it is non-null TreeTableColumn<S,T> oldCol = getTableColumn(); if (oldCol != null) { oldCol.getStyleClass().removeListener(weakColumnStyleClassListener); getStyleClass().removeAll(oldCol.getStyleClass()); oldCol.idProperty().removeListener(weakColumnIdListener); oldCol.styleProperty().removeListener(weakColumnStyleListener); String id = getId(); String style = getStyle(); if (id != null && id.equals(oldCol.getId())) { setId(null); } if (style != null && style.equals(oldCol.getStyle())) { setStyle(""); } } setTableColumn(col); if (col != null) { getStyleClass().addAll(col.getStyleClass()); col.getStyleClass().addListener(weakColumnStyleClassListener); col.idProperty().addListener(weakColumnIdListener); col.styleProperty().addListener(weakColumnStyleListener); possiblySetId(col.getId()); possiblySetStyle(col.getStyle()); } }
* Stylesheet Handling * *
/*************************************************************************** * * * Stylesheet Handling * * * **************************************************************************/
private static final String DEFAULT_STYLE_CLASS = "tree-table-cell"; private static final PseudoClass PSEUDO_CLASS_LAST_VISIBLE = PseudoClass.getPseudoClass("last-visible");
{@inheritDoc}
/** {@inheritDoc} */
@Override protected Skin<?> createDefaultSkin() { return new TreeTableCellSkin<S,T>(this); } private void possiblySetId(String idCandidate) { if (getId() == null || getId().isEmpty()) { setId(idCandidate); } } private void possiblySetStyle(String styleCandidate) { if (getStyle() == null || getStyle().isEmpty()) { setStyle(styleCandidate); } } /*************************************************************************** * * * Accessibility handling * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { switch (attribute) { case ROW_INDEX: return getIndex(); case COLUMN_INDEX: return columnIndex; case SELECTED: return isInCellSelectionMode() ? isSelected() : getTreeTableRow().isSelected(); default: return super.queryAccessibleAttribute(attribute, parameters); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void executeAccessibleAction(AccessibleAction action, Object... parameters) { switch (action) { case REQUEST_FOCUS: { TreeTableView<S> treeTableView = getTreeTableView(); if (treeTableView != null) { TreeTableViewFocusModel<S> fm = treeTableView.getFocusModel(); if (fm != null) { fm.focus(getIndex(), getTableColumn()); } } break; } default: super.executeAccessibleAction(action, parameters); } } }