Skip to content

Commit

Permalink
Merge pull request #1893 from malikoth/main
Browse files Browse the repository at this point in the history
Add a `clear` method that removes all children.
  • Loading branch information
freakboy3742 authored Apr 24, 2023
2 parents 207616f + 29f560d commit bc44914
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
1 change: 1 addition & 0 deletions changes/1893.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Widgets now have a `.clear()` method to remove all child widgets.
16 changes: 15 additions & 1 deletion core/src/toga/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,22 +154,36 @@ def remove(self, *children):
Any nominated child widget that is not a child of this widget will
not have any change in parentage.
Refreshes the widget after removal if any children were removed.
Raises ``ValueError`` if this widget cannot have children.
:param children: The child nodes to remove.
"""
removed = False

for child in children:
if child.parent is self:
removed = True
super().remove(child)

child.app = None
child.window = None

self._impl.remove_child(child._impl)

if self.window:
if self.window and removed:
self.window.content.refresh()

def clear(self):
"""Remove all child widgets of this node.
Refreshes the widget after removal if any children were removed.
Raises ``ValueError`` if this widget cannot have children.
"""
self.remove(*self.children)

@property
def app(self):
"""The App to which this widget belongs.
Expand Down
86 changes: 86 additions & 0 deletions core/tests/widgets/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,92 @@ def test_remove_multiple_children(widget):
window.content.refresh.assert_called_once_with()


def test_clear_all_children(widget):
"All children can be simultaneously removed from a widget"
# Add children to the widget
child1 = TestLeafWidget(id="child1_id")
child2 = TestLeafWidget(id="child2_id")
child3 = TestLeafWidget(id="child3_id")
widget.add(child1, child2, child3)

app = toga.App("Test", "com.example.test")
window = Mock()
widget.app = app
widget.window = window

assert widget.children == [child1, child2, child3]
for child in widget.children:
assert child.parent == widget
assert child.app == app
assert child.window == window

# Clear children
widget.clear()

# Parent doesn't know about the removed children, and vice versa
assert widget.children == []
assert child1.parent is None
assert child2.parent is None
assert child3.parent is None

# App and window have been reset on the removed widgets
assert child1.app is None
assert child1.window is None

assert child2.app is None
assert child2.window is None

assert child3.app is None
assert child3.window is None

# The impl's remove_child has been invoked thrice
assert_action_performed_with(widget, "remove child", child=child1._impl)
assert_action_performed_with(widget, "remove child", child=child2._impl)
assert_action_performed_with(widget, "remove child", child=child3._impl)

# The window layout has been refreshed once
window.content.refresh.assert_called_once_with()


def test_clear_no_children(widget):
"No changes are made (no-op) if widget has no children"
app = toga.App("Test", "com.example.test")
window = Mock()
widget.app = app
widget.window = window

assert widget.children == []

# Clear children
widget.clear()

# Parent doesn't have any children still
assert widget.children == []

# The window layout has not been refreshed
window.content.refresh.assert_not_called()


def test_clear_leaf_node():
"No changes are made to leaf node that cannot have children"
leaf = TestLeafWidget()
app = toga.App("Test", "com.example.test")
window = Mock()
leaf.app = app
leaf.window = window

assert leaf.children == []

# Clear children
leaf.clear()

# Parent doesn't have any children still
assert leaf.children == []

# The window layout has not been refreshed
window.content.refresh.assert_not_called()


def test_remove_from_non_parent(widget):
"Trying to remove a child from a widget other than it's parent is a no-op"
# Create a second parent widget, and add a child to it
Expand Down

0 comments on commit bc44914

Please sign in to comment.