/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package javafx.scene.control;
import javafx.css.
PseudoClass;
import com.sun.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 {@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>
* </p>
*
* @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'.
*/
public
TreeTableCell() {
getStyleClass().
addAll(
DEFAULT_STYLE_CLASS);
setAccessibleRole(
AccessibleRole.
TREE_TABLE_CELL);
updateColumnIndex();
}
/***************************************************************************
* *
* Private fields *
* *
**************************************************************************/
// package for testing
boolean
lockItemOnEdit = false;
/***************************************************************************
* *
* 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.
*/
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.
*/
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.
*/
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} */
@
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} */
@
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} */
@
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} */
@
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} */
@
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;
}
boolean
isFocusedNow =
fm != null &&
fm.
isFocused(
getIndex(),
getTableColumn());
setFocused(
isFocusedNow);
}
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.
*
* @expert 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.
*/
public final void
updateTreeTableView(
TreeTableView<S>
tv) {
setTreeTableView(
tv);
}
/**
* Updates the TreeTableRow associated with this TreeTableCell.
*
* @expert 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.
*/
public final void
updateTreeTableRow(
TreeTableRow<S>
treeTableRow) {
this.
setTreeTableRow(
treeTableRow);
}
/**
* Updates the TreeTableColumn associated with this TreeTableCell.
*
* @expert 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.
*/
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 *
* *
**************************************************************************/
private static final
String DEFAULT_STYLE_CLASS = "tree-table-cell";
private static final
PseudoClass PSEUDO_CLASS_LAST_VISIBLE =
PseudoClass.
getPseudoClass("last-visible");
/** {@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 *
* *
**************************************************************************/
@
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);
}
}
@
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);
}
}
}