/*
 * Copyright (c) 2011, 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.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
import javafx.scene.control.skin.TreeCellSkin;
import javafx.collections.WeakListChangeListener;
import java.lang.ref.WeakReference;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;

The Cell type used with the TreeView control. In addition to the API defined on IndexedCell, the TreeCell exposes additional states and pseudo classes for use by CSS.

A TreeCell watches the selection model of the TreeView for which it is associated, ensuring that it visually indicates to the user whether it is selected. When a TreeCell is selected, this is exposed both via the selected property, as well as via the 'selected' CSS pseudo class state.

Due to the fact that TreeCell extends from IndexedCell, each TreeCell also provides an index property. The index will be updated as cells are expanded and collapsed, and therefore should be considered a view index rather than a model index.

Finally, each TreeCell also has a reference back to the TreeView that it is being used with. Each TreeCell belongs to one and only one TreeView.

Type parameters:
  • <T> – The type of the value contained within the TreeItem property.
See Also:
Since:JavaFX 2.0
/** * The {@link Cell} type used with the {@link TreeView} control. In addition to * the API defined on {@link IndexedCell}, the TreeCell * exposes additional states and pseudo classes for use by CSS. * <p> * A TreeCell watches the selection model of the TreeView for which it is * associated, ensuring that it visually indicates to the user whether it is * selected. When a TreeCell is selected, this is exposed both via the * {@link #selectedProperty() selected} property, as well as via the 'selected' * CSS pseudo class state. * <p> * Due to the fact that TreeCell extends from {@link IndexedCell}, each TreeCell * also provides an {@link #indexProperty() index} property. The index will be * updated as cells are expanded and collapsed, and therefore should be * considered a view index rather than a model index. * <p> * Finally, each TreeCell also has a reference back to the TreeView that it is * being used with. Each TreeCell belongs to one and only one TreeView. * * @see TreeView * @see TreeItem * @param <T> The type of the value contained within the * {@link #treeItemProperty() TreeItem} property. * @since JavaFX 2.0 */
public class TreeCell<T> extends IndexedCell<T> { /*************************************************************************** * * * Constructors * * * **************************************************************************/
Creates a default TreeCell instance.
/** * Creates a default TreeCell instance. */
public TreeCell() { getStyleClass().addAll(DEFAULT_STYLE_CLASS); setAccessibleRole(AccessibleRole.TREE_ITEM); }
* Callbacks and events * *
/*************************************************************************** * * * Callbacks and events * * * **************************************************************************/
private final ListChangeListener<Integer> selectedListener = c -> { updateSelection(); };
Listens to the selectionModel property on the TreeView. Whenever the entire model is changed, we have to unhook the weakSelectedListener and update the selection.
/** * Listens to the selectionModel property on the TreeView. Whenever the entire model is changed, * we have to unhook the weakSelectedListener and update the selection. */
private final ChangeListener<MultipleSelectionModel<TreeItem<T>>> selectionModelPropertyListener = new ChangeListener<MultipleSelectionModel<TreeItem<T>>>() { @Override public void changed(ObservableValue<? extends MultipleSelectionModel<TreeItem<T>>> observable, MultipleSelectionModel<TreeItem<T>> oldValue, MultipleSelectionModel<TreeItem<T>> newValue) { if (oldValue != null) { oldValue.getSelectedIndices().removeListener(weakSelectedListener); } if (newValue != null) { newValue.getSelectedIndices().addListener(weakSelectedListener); } updateSelection(); } }; private final InvalidationListener focusedListener = valueModel -> { updateFocus(); };
Listens to the focusModel property on the TreeView. Whenever the entire model is changed, we have to unhook the weakFocusedListener and update the focus.
/** * Listens to the focusModel property on the TreeView. Whenever the entire model is changed, * we have to unhook the weakFocusedListener and update the focus. */
private final ChangeListener<FocusModel<TreeItem<T>>> focusModelPropertyListener = new ChangeListener<FocusModel<TreeItem<T>>>() { @Override public void changed(ObservableValue<? extends FocusModel<TreeItem<T>>> observable, FocusModel<TreeItem<T>> oldValue, FocusModel<TreeItem<T>> newValue) { if (oldValue != null) { oldValue.focusedIndexProperty().removeListener(weakFocusedListener); } if (newValue != null) { newValue.focusedIndexProperty().addListener(weakFocusedListener); } updateFocus(); } }; private final InvalidationListener editingListener = valueModel -> { updateEditing(); }; private final InvalidationListener leafListener = new InvalidationListener() { @Override public void invalidated(Observable valueModel) { // necessary to update the disclosure node in the skin when the // leaf property changes TreeItem<T> treeItem = getTreeItem(); if (treeItem != null) { requestLayout(); } } }; /* proxy pseudo-class state change from treeItem's expandedProperty */ private boolean oldIsExpanded; private final InvalidationListener treeItemExpandedInvalidationListener = new InvalidationListener() { @Override public void invalidated(Observable o) { boolean isExpanded = ((BooleanProperty)o).get(); pseudoClassStateChanged(EXPANDED_PSEUDOCLASS_STATE, isExpanded); pseudoClassStateChanged(COLLAPSED_PSEUDOCLASS_STATE, !isExpanded); if (isExpanded != oldIsExpanded) { notifyAccessibleAttributeChanged(AccessibleAttribute.EXPANDED); } oldIsExpanded = isExpanded; } }; private final InvalidationListener rootPropertyListener = observable -> { updateItem(-1); }; private final WeakListChangeListener<Integer> weakSelectedListener = new WeakListChangeListener<Integer>(selectedListener); private final WeakChangeListener<MultipleSelectionModel<TreeItem<T>>> weakSelectionModelPropertyListener = new WeakChangeListener<MultipleSelectionModel<TreeItem<T>>>(selectionModelPropertyListener); private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener); private final WeakChangeListener<FocusModel<TreeItem<T>>> weakFocusModelPropertyListener = new WeakChangeListener<FocusModel<TreeItem<T>>>(focusModelPropertyListener); private final WeakInvalidationListener weakEditingListener = new WeakInvalidationListener(editingListener); private final WeakInvalidationListener weakLeafListener = new WeakInvalidationListener(leafListener); private final WeakInvalidationListener weakTreeItemExpandedInvalidationListener = new WeakInvalidationListener(treeItemExpandedInvalidationListener); private final WeakInvalidationListener weakRootPropertyListener = new WeakInvalidationListener(rootPropertyListener);
* Properties * *
/*************************************************************************** * * * Properties * * * **************************************************************************/
// --- TreeItem private ReadOnlyObjectWrapper<TreeItem<T>> treeItem = new ReadOnlyObjectWrapper<TreeItem<T>>(this, "treeItem") { TreeItem<T> oldValue = null; @Override protected void invalidated() { if (oldValue != null) { oldValue.expandedProperty().removeListener(weakTreeItemExpandedInvalidationListener); } oldValue = get(); if (oldValue != null) { oldIsExpanded = oldValue.isExpanded(); oldValue.expandedProperty().addListener(weakTreeItemExpandedInvalidationListener); // fake an invalidation to ensure updated pseudo-class state weakTreeItemExpandedInvalidationListener.invalidated(oldValue.expandedProperty()); } } }; private void setTreeItem(TreeItem<T> value) { treeItem.set(value); }
Returns the TreeItem currently set in this TreeCell.
Returns:the TreeItem currently set in this TreeCell
/** * Returns the TreeItem currently set in this TreeCell. * @return the TreeItem currently set in this TreeCell */
public final TreeItem<T> getTreeItem() { return treeItem.get(); }
Each TreeCell represents at most a single TreeItem, which is represented by this property.
Returns:the TreeItem property representing this TreeCell
/** * Each TreeCell represents at most a single {@link TreeItem}, which is * represented by this property. * @return the TreeItem property representing this TreeCell */
public final ReadOnlyObjectProperty<TreeItem<T>> treeItemProperty() { return treeItem.getReadOnlyProperty(); } // --- Disclosure Node private ObjectProperty<Node> disclosureNode = new SimpleObjectProperty<Node>(this, "disclosureNode");
The node to use as the "disclosure" triangle, or toggle, used for expanding and collapsing items. This is only used in the case of an item in the tree which contains child items. If not specified, the TreeCell's Skin implementation is responsible for providing a default disclosure node.
Params:
  • value – the disclosure node
/** * The node to use as the "disclosure" triangle, or toggle, used for * expanding and collapsing items. This is only used in the case of * an item in the tree which contains child items. If not specified, the * TreeCell's Skin implementation is responsible for providing a default * disclosure node. * @param value the disclosure node */
public final void setDisclosureNode(Node value) { disclosureNodeProperty().set(value); }
Returns the current disclosure node set in this TreeCell.
Returns:the current disclosure node set in this TreeCell
/** * Returns the current disclosure node set in this TreeCell. * @return the current disclosure node set in this TreeCell */
public final Node getDisclosureNode() { return disclosureNode.get(); }
The disclosure node is commonly seen represented as a triangle that rotates on screen to indicate whether or not the TreeItem that it is placed beside is expanded or collapsed.
Returns:the disclosure node
/** * The disclosure node is commonly seen represented as a triangle that rotates * on screen to indicate whether or not the TreeItem that it is placed * beside is expanded or collapsed. * @return the disclosure node */
public final ObjectProperty<Node> disclosureNodeProperty() { return disclosureNode; } // --- TreeView private ReadOnlyObjectWrapper<TreeView<T>> treeView = new ReadOnlyObjectWrapper<TreeView<T>>() { private WeakReference<TreeView<T>> weakTreeViewRef; @Override protected void invalidated() { MultipleSelectionModel<TreeItem<T>> sm; FocusModel<TreeItem<T>> fm; if (weakTreeViewRef != null) { TreeView<T> oldTreeView = weakTreeViewRef.get(); if (oldTreeView != null) { // remove old listeners sm = oldTreeView.getSelectionModel(); if (sm != null) { sm.getSelectedIndices().removeListener(weakSelectedListener); } fm = oldTreeView.getFocusModel(); if (fm != null) { fm.focusedIndexProperty().removeListener(weakFocusedListener); } oldTreeView.editingItemProperty().removeListener(weakEditingListener); oldTreeView.focusModelProperty().removeListener(weakFocusModelPropertyListener); oldTreeView.selectionModelProperty().removeListener(weakSelectionModelPropertyListener); oldTreeView.rootProperty().removeListener(weakRootPropertyListener); } weakTreeViewRef = null; } TreeView<T> treeView = get(); if (treeView != null) { sm = treeView.getSelectionModel(); if (sm != null) { // listening for changes to treeView.selectedIndex and IndexedCell.index, // to determine if this cell is selected sm.getSelectedIndices().addListener(weakSelectedListener); } fm = treeView.getFocusModel(); if (fm != null) { // similar to above, but this time for focus fm.focusedIndexProperty().addListener(weakFocusedListener); } treeView.editingItemProperty().addListener(weakEditingListener); treeView.focusModelProperty().addListener(weakFocusModelPropertyListener); treeView.selectionModelProperty().addListener(weakSelectionModelPropertyListener); treeView.rootProperty().addListener(weakRootPropertyListener); weakTreeViewRef = new WeakReference<TreeView<T>>(treeView); } updateItem(-1); requestLayout(); } @Override public Object getBean() { return TreeCell.this; } @Override public String getName() { return "treeView"; } }; private void setTreeView(TreeView<T> value) { treeView.set(value); }
Returns the TreeView associated with this TreeCell.
Returns:the TreeView associated with this TreeCell
/** * Returns the TreeView associated with this TreeCell. * @return the TreeView associated with this TreeCell */
public final TreeView<T> getTreeView() { return treeView.get(); }
A TreeCell is explicitly linked to a single TreeView instance, which is represented by this property.
Returns:the TreeView property of this TreeCell
/** * A TreeCell is explicitly linked to a single {@link TreeView} instance, * which is represented by this property. * @return the TreeView property of this TreeCell */
public final ReadOnlyObjectProperty<TreeView<T>> treeViewProperty() { return treeView.getReadOnlyProperty(); } /*************************************************************************** * * * Public API * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override public void startEdit() { if (isEditing()) return; final TreeView<T> tree = getTreeView(); if (! isEditable() || (tree != null && ! tree.isEditable())) { // if (Logging.getControlsLogger().isLoggable(PlatformLogger.SEVERE)) { // Logging.getControlsLogger().severe( // "Can not call TreeCell.startEdit() on this TreeCell, as it " // + "is not allowed to enter its editing state (TreeCell: " // + this + ", TreeView: " + tree + ")."); // } return; } updateItem(-1); // it makes sense to get the cell into its editing state before firing // the event to the TreeView below, so that's what we're doing here // by calling super.startEdit(). super.startEdit(); // Inform the TreeView of the edit starting. if (tree != null) { tree.fireEvent(new TreeView.EditEvent<T>(tree, TreeView.<T>editStartEvent(), getTreeItem(), getItem(), null)); tree.requestFocus(); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void commitEdit(T newValue) { if (! isEditing()) return; final TreeItem<T> treeItem = getTreeItem(); final TreeView<T> tree = getTreeView(); if (tree != null) { // Inform the TreeView of the edit being ready to be committed. tree.fireEvent(new TreeView.EditEvent<T>(tree, TreeView.<T>editCommitEvent(), treeItem, getItem(), newValue)); } // 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 if (treeItem != null) { treeItem.setValue(newValue); updateTreeItem(treeItem); updateItem(newValue, false); } if (tree != null) { // reset the editing item in the TreetView tree.edit(null); // request focus back onto the tree, only if the current focus // owner has the tree as a parent (otherwise the user might have // clicked out of the tree entirely and given focus to something else. // It would be rude of us to request it back again. ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void cancelEdit() { if (! isEditing()) return; TreeView<T> tree = getTreeView(); super.cancelEdit(); if (tree != null) { // reset the editing index on the TreeView if (updateEditingIndex) tree.edit(null); // request focus back onto the tree, only if the current focus // owner has the tree as a parent (otherwise the user might have // clicked out of the tree entirely and given focus to something else. // It would be rude of us to request it back again. ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tree); tree.fireEvent(new TreeView.EditEvent<T>(tree, TreeView.<T>editCancelEvent(), getTreeItem(), getItem(), null)); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected Skin<?> createDefaultSkin() { return new TreeCellSkin<T>(this); } /*************************************************************************** * * * Private Implementation * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override void indexChanged(int oldIndex, int newIndex) { super.indexChanged(oldIndex, newIndex); // when the cell index changes, this may result in the cell // changing state to be selected and/or focused. 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 { updateItem(oldIndex); updateSelection(); updateFocus(); } } private boolean isFirstRun = true; private void updateItem(int oldIndex) { TreeView<T> tv = getTreeView(); if (tv == null) return; // Compute whether the index for this cell is for a real item int index = getIndex(); boolean valid = index >=0 && index < tv.getExpandedItemCount(); final boolean isEmpty = isEmpty(); final TreeItem<T> oldTreeItem = getTreeItem(); // Cause the cell to update itself outer: if (valid) { // update the TreeCell state. // get the new treeItem that is about to go in to the TreeCell TreeItem<T> newTreeItem = tv.getTreeItem(index); T newValue = newTreeItem == null ? null : newTreeItem.getValue(); T oldValue = oldTreeItem == null ? null : oldTreeItem.getValue(); // For the sake of RT-14279, it is important that the order of these // method calls is as shown below. If the order is switched, it is // likely that events will be fired where the item is null, even // though calling cell.getTreeItem().getValue() returns the value // as expected // 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-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; } } updateTreeItem(newTreeItem); 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 && oldTreeItem != null) || isFirstRun) { updateTreeItem(null); updateItem(null, true); isFirstRun = false; } } } private void updateSelection() { if (isEmpty()) return; if (getIndex() == -1 || getTreeView() == null) return; SelectionModel<TreeItem<T>> sm = getTreeView().getSelectionModel(); if (sm == null) { updateSelected(false); return; } boolean isSelected = sm.isSelected(getIndex()); if (isSelected() == isSelected) return; updateSelected(isSelected); } private void updateFocus() { if (getIndex() == -1 || getTreeView() == null) return; FocusModel<TreeItem<T>> fm = getTreeView().getFocusModel(); if (fm == null) { setFocused(false); return; } setFocused(fm.isFocused(getIndex())); } private boolean updateEditingIndex = true; private void updateEditing() { final int index = getIndex(); final TreeView<T> tree = getTreeView(); final TreeItem<T> treeItem = getTreeItem(); final TreeItem<T> editItem = tree == null ? null : tree.getEditingItem(); final boolean editing = isEditing(); if (index == -1 || tree == null || treeItem == null) return; final boolean match = treeItem.equals(editItem); // If my tree item is the item being edited and I'm not currently in // the edit mode, then I need to enter the edit mode if (match && !editing) { startEdit(); } else if (! match && editing) { // If my tree item 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 tree.edit(null) 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; } } /*************************************************************************** * * * Expert API * * * **************************************************************************/
Updates the TreeView associated with this TreeCell.
Params:
  • tree – The new TreeView that should be associated with this TreeCell. 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.
/** * Updates the TreeView associated with this TreeCell. * * @param tree The new TreeView that should be associated with this TreeCell. * 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. */
public final void updateTreeView(TreeView<T> tree) { setTreeView(tree); }
Updates the TreeItem associated with this TreeCell.
Params:
  • treeItem – The new TreeItem that should be associated with this TreeCell. 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.
/** * Updates the TreeItem associated with this TreeCell. * * @param treeItem The new TreeItem that should be associated with this * TreeCell. * 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. */
public final void updateTreeItem(TreeItem<T> treeItem) { TreeItem<T> _treeItem = getTreeItem(); if (_treeItem != null) { _treeItem.leafProperty().removeListener(weakLeafListener); } setTreeItem(treeItem); if (treeItem != null) { treeItem.leafProperty().addListener(weakLeafListener); } }
* Stylesheet Handling * *
/*************************************************************************** * * * Stylesheet Handling * * * **************************************************************************/
private static final String DEFAULT_STYLE_CLASS = "tree-cell"; private static final PseudoClass EXPANDED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("expanded"); private static final PseudoClass COLLAPSED_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("collapsed"); /*************************************************************************** * * * Accessibility handling * * * **************************************************************************/
{@inheritDoc}
/** {@inheritDoc} */
@Override public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) { TreeItem<T> treeItem = getTreeItem(); TreeView<T> treeView = getTreeView(); switch (attribute) { case TREE_ITEM_PARENT: { if (treeView == null) return null; if (treeItem == null) return null; TreeItem<T> parent = treeItem.getParent(); if (parent == null) return null; int parentIndex = treeView.getRow(parent); return treeView.queryAccessibleAttribute(AccessibleAttribute.ROW_AT_INDEX, parentIndex); } case TREE_ITEM_COUNT: { if (treeItem == null) return 0; if (!treeItem.isExpanded()) return 0; return treeItem.getChildren().size(); } case TREE_ITEM_AT_INDEX: { if (treeItem == null) return null; if (!treeItem.isExpanded()) return null; int index = (Integer)parameters[0]; if (index >= treeItem.getChildren().size()) return null; TreeItem<T> child = treeItem.getChildren().get(index); if (child == null) return null; int childIndex = treeView.getRow(child); return treeView.queryAccessibleAttribute(AccessibleAttribute.ROW_AT_INDEX, childIndex); } case LEAF: return treeItem == null ? true : treeItem.isLeaf(); case EXPANDED: return treeItem == null ? false : treeItem.isExpanded(); case INDEX: return getIndex(); case SELECTED: return isSelected(); case DISCLOSURE_LEVEL: { return treeView == null ? 0 : treeView.getTreeItemLevel(treeItem); } default: return super.queryAccessibleAttribute(attribute, parameters); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void executeAccessibleAction(AccessibleAction action, Object... parameters) { switch (action) { case EXPAND: { TreeItem<T> treeItem = getTreeItem(); if (treeItem != null) treeItem.setExpanded(true); break; } case COLLAPSE: { TreeItem<T> treeItem = getTreeItem(); if (treeItem != null) treeItem.setExpanded(false); break; } case REQUEST_FOCUS: { TreeView<T> treeView = getTreeView(); if (treeView != null) { FocusModel<TreeItem<T>> fm = treeView.getFocusModel(); if (fm != null) { fm.focus(getIndex()); } } break; } default: super.executeAccessibleAction(action); } } }