enhancement
major
minor
major
minor
minor
#29636
TL Views: a click on a <tree> node clears the selection channel before setting it, so every dependent display and command flips to empty and back
Observed in tl-demo-react, Demos → Tree Demo, while verifying #29635: a single click on a node makes the server send two patches for the display of the selected channel - first {"text":""}, then {"text":"M3"} - and the toolbar commands bound to the selection are disabled and re-enabled in between. The settled state is correct; the round trip is redundant and, with a slower connection or a heavier dependent view, a visible flicker.
Ursache
ReactTreeControl.selectOnly(node) (single-select mode, and the selection step of an activation) replaces the selection in two steps:
{{{#!java _selectionModel.clear(); _selectionModel.setSelected(node, true); }}}
Each step fires a selection event. TreeSelectionBinding.handleSelectionChanged writes the channel on every event: null for the empty selection, then the object. Every listener of the channel - derived channels, the displays bound to it, the executability of the commands whose input it is - runs twice, and the client receives the intermediate empty state as patches.
The same holds for a Shift range in multi-select mode: handleSelect calls setSelected once per node of the range, so the channel is written once per node and a display bound to it shows the growing range.
SelectionModel.setSelection(Set) replaces the selection in one step with one event; a single-selection model's setSelected(obj, true) already replaces the previous selection on its own.
Lösung
ReactTreeControl replaces the selection in one step, so that one selection event reaches the channel per gesture:
- selectOnly (plain click, double-click/Enter activation) calls _selectionModel.setSelection(Set.of(node)). Both selection models the view layer wires in (DefaultSingleSelectionModel, DefaultMultiSelectionModel) fire exactly one event for it, and none when the node is already the selection.
- The Shift range collects the selectable nodes of the range and applies them with one addToSelection or removeFromSelection call, depending on whether the anchor was added to or taken out of the selection.
- The Ctrl toggle was one event already and is unchanged. TreeSelectionBinding, the selection models and the client are untouched.
The command ids SELECT_COMMAND / ACTIVATE_COMMAND and the state keys NODES / NODE_ID of ReactTreeControl are public constants, as on the other React controls, so that tests send the gestures the way the client does without re-quoting the wire names.
Tests: TestReactTreeControlSelection (tl-layout-react) sends the select and activate commands through ReactControl.executeCommand and asserts one selection event per plain click, Ctrl click, Shift range (adding and removing) and activation, and no event for a click on the already selected node. TestTreeSelectionBinding asserts that two clicks write exactly [A, B] to the channel and that a Shift range arrives as one set value. Verified in tl-demo-react, Tree Demo: a MutationObserver on the "Selected node" display records exactly one text value per gesture, never an empty intermediate one.