|
@@ -4,7 +4,7 @@ import inspect
|
|
import re
|
|
import re
|
|
from copy import copy, deepcopy
|
|
from copy import copy, deepcopy
|
|
from pathlib import Path
|
|
from pathlib import Path
|
|
-from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Optional, Sequence, Union
|
|
|
|
|
|
+from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Union
|
|
|
|
|
|
from typing_extensions import Self
|
|
from typing_extensions import Self
|
|
|
|
|
|
@@ -304,19 +304,24 @@ class Element(Visibility):
|
|
target_id = globals._socket_id or self.client.id # pylint: disable=protected-access
|
|
target_id = globals._socket_id or self.client.id # pylint: disable=protected-access
|
|
outbox.enqueue_message('run_method', data, target_id)
|
|
outbox.enqueue_message('run_method', data, target_id)
|
|
|
|
|
|
- def _collect_descendant_ids(self) -> List[int]:
|
|
|
|
- ids: List[int] = [self.id]
|
|
|
|
|
|
+ def _collect_descendants(self, *, include_self: bool = False) -> List[Element]:
|
|
|
|
+ elements: List[Element] = [self] if include_self else []
|
|
for child in self:
|
|
for child in self:
|
|
- ids.extend(child._collect_descendant_ids()) # pylint: disable=protected-access
|
|
|
|
- return ids
|
|
|
|
|
|
+ elements.extend(child._collect_descendants(include_self=True)) # pylint: disable=protected-access
|
|
|
|
+ return elements
|
|
|
|
+
|
|
|
|
+ @staticmethod
|
|
|
|
+ def _delete_elements(elements: Iterable[Element]) -> None:
|
|
|
|
+ binding.remove(elements, Element)
|
|
|
|
+ for element in elements:
|
|
|
|
+ element._deleted = True # pylint: disable=protected-access
|
|
|
|
+ del element.client.elements[element.id]
|
|
|
|
+ outbox.enqueue_delete(element)
|
|
|
|
|
|
def clear(self) -> None:
|
|
def clear(self) -> None:
|
|
"""Remove all child elements."""
|
|
"""Remove all child elements."""
|
|
- descendants = [self.client.elements[id] for id in self._collect_descendant_ids()[1:]]
|
|
|
|
- binding.remove(descendants, Element)
|
|
|
|
- for element in descendants:
|
|
|
|
- element.delete()
|
|
|
|
- del self.client.elements[element.id]
|
|
|
|
|
|
+ descendants = self._collect_descendants()
|
|
|
|
+ self._delete_elements(descendants)
|
|
for slot in self.slots.values():
|
|
for slot in self.slots.values():
|
|
slot.children.clear()
|
|
slot.children.clear()
|
|
self.update()
|
|
self.update()
|
|
@@ -344,19 +349,25 @@ class Element(Visibility):
|
|
if isinstance(element, int):
|
|
if isinstance(element, int):
|
|
children = list(self)
|
|
children = list(self)
|
|
element = children[element]
|
|
element = children[element]
|
|
- binding.remove([element], Element)
|
|
|
|
- element.delete()
|
|
|
|
- del self.client.elements[element.id]
|
|
|
|
- for slot in self.slots.values():
|
|
|
|
- slot.children[:] = [e for e in slot if e.id != element.id]
|
|
|
|
|
|
+ elements = element._collect_descendants(include_self=True) # pylint: disable=protected-access
|
|
|
|
+ self._delete_elements(elements)
|
|
|
|
+ assert element.parent_slot is not None
|
|
|
|
+ element.parent_slot.children.remove(element)
|
|
self.update()
|
|
self.update()
|
|
|
|
|
|
def delete(self) -> None:
|
|
def delete(self) -> None:
|
|
- """Perform cleanup when the element is deleted."""
|
|
|
|
- self._deleted = True
|
|
|
|
- outbox.enqueue_delete(self)
|
|
|
|
|
|
+ """Delete the element."""
|
|
|
|
+ self._delete_elements([self])
|
|
|
|
+ assert self.parent_slot is not None
|
|
|
|
+ self.parent_slot.children.remove(self)
|
|
|
|
+
|
|
|
|
+ def _on_delete(self) -> None:
|
|
|
|
+ """Called when the element is deleted.
|
|
|
|
+
|
|
|
|
+ This method can be overridden in subclasses to perform cleanup tasks.
|
|
|
|
+ """
|
|
|
|
|
|
@property
|
|
@property
|
|
- def is_deleted(self) -> None:
|
|
|
|
|
|
+ def is_deleted(self) -> bool:
|
|
"""Whether the element has been deleted."""
|
|
"""Whether the element has been deleted."""
|
|
return self._deleted
|
|
return self._deleted
|