mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Allow setting a new label when performing a clear on a Tree
See #1437 for background. While it would be ideal to allow for the complete emptying of a Tree, the root node is required (and it's part of the construction of a Tree). So, here, when clearing the Tree we optionally allow for a new label to be given. Ideally we'll also allow for fresh data to be provided too; but there's a wrinkle there in knowing the difference between the data being None, and no data being provided (so the current root's data being carried over). Following the method of defaulting used in __init__ would cause problems. As such, rather than roll all of this into one commit, this goes with the basic requirement and the solution for data will follow. Note this also starts some unit tests for the clearing of a Tree.
This commit is contained in:
@@ -560,12 +560,17 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
||||
label = self.render_label(node, NULL_STYLE, NULL_STYLE)
|
||||
return label.cell_len
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear all nodes under root."""
|
||||
def clear(self, label: TextType | None = None) -> None:
|
||||
"""Clear all nodes under root.
|
||||
|
||||
Args:
|
||||
label: An optional new label for the root node. If not provided
|
||||
the current root node's label will be used.
|
||||
"""
|
||||
self._line_cache.clear()
|
||||
self._tree_lines_cached = None
|
||||
self._current_id = 0
|
||||
root_label = self.root._label
|
||||
root_label = self.root._label if label is None else label
|
||||
root_data = self.root.data
|
||||
self.root = TreeNode(
|
||||
self,
|
||||
|
||||
62
tests/tree/test_tree_clearing.py
Normal file
62
tests/tree/test_tree_clearing.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Tree
|
||||
|
||||
|
||||
class VerseBody:
|
||||
pass
|
||||
|
||||
|
||||
class VerseStar(VerseBody):
|
||||
pass
|
||||
|
||||
|
||||
class VersePlanet(VerseBody):
|
||||
pass
|
||||
|
||||
|
||||
class VerseMoon(VerseBody):
|
||||
pass
|
||||
|
||||
|
||||
class TestTree(Tree[VerseBody]):
|
||||
pass
|
||||
|
||||
|
||||
class TreeClearApp(App[None]):
|
||||
"""Tree clearing test app."""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield TestTree("White Sun", data=VerseStar())
|
||||
|
||||
def on_mount(self) -> None:
|
||||
tree = self.query_one(TestTree)
|
||||
node = tree.root.add("Londinium", VersePlanet())
|
||||
node.add_leaf("Balkerne", VerseMoon())
|
||||
node.add_leaf("Colchester", VerseMoon())
|
||||
node = tree.root.add("Sihnon", VersePlanet())
|
||||
node.add_leaf("Airen", VerseMoon())
|
||||
node.add_leaf("Xiaojie", VerseMoon())
|
||||
|
||||
|
||||
async def test_tree_simple_clear() -> None:
|
||||
"""Clearing a tree should keep the old label and data."""
|
||||
async with TreeClearApp().run_test() as pilot:
|
||||
tree = pilot.app.query_one(TestTree)
|
||||
assert len(tree.root.children) > 1
|
||||
pilot.app.query_one(TestTree).clear()
|
||||
assert len(tree.root.children) == 0
|
||||
assert str(tree.root.label) == "White Sun"
|
||||
assert isinstance(tree.root.data, VerseStar)
|
||||
|
||||
|
||||
async def test_tree_new_label_clear() -> None:
|
||||
"""Clearing a tree with a new label should use the new label and keep the old data."""
|
||||
async with TreeClearApp().run_test() as pilot:
|
||||
tree = pilot.app.query_one(TestTree)
|
||||
assert len(tree.root.children) > 1
|
||||
pilot.app.query_one(TestTree).clear("Jiangyin")
|
||||
assert len(tree.root.children) == 0
|
||||
assert str(tree.root.label) == "Jiangyin"
|
||||
assert isinstance(tree.root.data, VerseStar)
|
||||
Reference in New Issue
Block a user