Skip to content

Commit

Permalink
Fix delete of ResourceGroup to update do-not-download badges in Entit…
Browse files Browse the repository at this point in the history
…yTree properly
  • Loading branch information
davidfstr committed Jan 21, 2024
1 parent d28dff1 commit 77ae84f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 25 deletions.
4 changes: 0 additions & 4 deletions src/crystal/browser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,10 +574,6 @@ def _on_forget_entity(self, event) -> None:
assert selected_or_related_entity is not None

selected_or_related_entity.delete()

# TODO: This update() should happen in response to an event
# fired by the entity itself.
self.entity_tree.update()

def _on_download_entity(self, event) -> None:
selected_entity = self.entity_tree.selected_entity
Expand Down
29 changes: 21 additions & 8 deletions src/crystal/browser/entitytree.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,16 @@ def name_of_selection(self) -> Optional[str]:

# === Updates ===

# TODO: Can this be marked with @fg_affinity?
def update(self):
"""
Updates the nodes in this tree, usually due to a project change.
"""
self.root.update_descendants()

# === Event: Resource Did Instantiate ===
# === Events: Resource Lifecycle ===

# TODO: Can this be marked with @fg_affinity?
def resource_did_instantiate(self, resource: Resource) -> None:
# TODO: Optimize to only refresh those groups that could potentially
# be affected by this particular resource being instantiated
Expand All @@ -160,19 +162,22 @@ def _refresh_group_nodes_now(self) -> None:
finally:
self._group_nodes_need_updating = False

# === Event: Resource Revision Did Instantiate ===
# === Events: Resource Revision Lifecycle ===

# TODO: Can this be marked with @fg_affinity? Then remove interior fg_call_later().
def resource_revision_did_instantiate(self, revision: ResourceRevision) -> None:
fg_call_later(lambda:
self.root.update_icon_set_of_descendants_with_resource(revision.resource))

# === Event: Root Resource Did Instantiate ===
# === Events: Root Resource Lifecycle ===

# TODO: Can this be marked with @fg_affinity?
def root_resource_did_instantiate(self, root_resource: RootResource) -> None:
self.update()

# === Event: Resource Group Did Instantiate ===
# === Events: Resource Group Lifecycle ===

# TODO: Can this be marked with @fg_affinity? Then remove interior fg_call_later().
def resource_group_did_instantiate(self, group: ResourceGroup) -> None:
self.update()

Expand All @@ -181,11 +186,19 @@ def resource_group_did_instantiate(self, group: ResourceGroup) -> None:
fg_call_later(lambda:
self.root.update_icon_set_of_descendants_in_group(group))

# === Event: Resource Group Did Change Do-Not-Download ===

@fg_affinity
def resource_group_did_change_do_not_download(self, group: ResourceGroup) -> None:
fg_call_later(lambda:
self.root.update_icon_set_of_descendants_in_group(group))
self.root.update_icon_set_of_descendants_in_group(group)

@fg_affinity
def resource_group_will_forget(self, group: ResourceGroup) -> None:
pass

@fg_affinity
def resource_group_did_forget(self, group: ResourceGroup) -> None:
self.update()

self.root.update_icon_set_of_descendants_in_group(group)

# === Event: Min Fetch Date Did Change ===

Expand Down
43 changes: 33 additions & 10 deletions src/crystal/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ def add_task(self, task: Task) -> None:
if task_was_complete:
self.root_task.child_task_did_complete(task)

# === Events ===
# === Events: Resource Lifecycle ===

# Called when a new Resource is created after the project has loaded
def _resource_did_instantiate(self, resource: Resource) -> None:
Expand All @@ -1341,13 +1341,6 @@ def _resource_did_instantiate(self, resource: Resource) -> None:
if hasattr(lis, 'resource_did_instantiate'):
lis.resource_did_instantiate(resource) # type: ignore[attr-defined]

# Called when a new ResourceRevision is created after the project has loaded
def _resource_revision_did_instantiate(self, revision: ResourceRevision) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_revision_did_instantiate'):
lis.resource_revision_did_instantiate(revision) # type: ignore[attr-defined]

def _resource_did_alter_url(self,
resource: Resource, old_url: str, new_url: str) -> None:
del self._resource_for_url[old_url]
Expand All @@ -1365,27 +1358,51 @@ def _resource_will_delete(self, resource: Resource) -> None:
for rg in self.resource_groups:
rg._resource_will_delete(resource)

# === Events: Resource Revision Lifecycle ===

# Called when a new ResourceRevision is created after the project has loaded
def _resource_revision_did_instantiate(self, revision: ResourceRevision) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_revision_did_instantiate'):
lis.resource_revision_did_instantiate(revision) # type: ignore[attr-defined]

# === Events: Root Resource Lifecycle ===

# Called when a new RootResource is created after the project has loaded
def _root_resource_did_instantiate(self, root_resource: RootResource) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'root_resource_did_instantiate'):
lis.root_resource_did_instantiate(root_resource) # type: ignore[attr-defined]

# === Events: Resource Group Lifecycle ===

# Called when a new ResourceGroup is created after the project has loaded
def _resource_group_did_instantiate(self, group: ResourceGroup) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_group_did_instantiate'):
lis.resource_group_did_instantiate(group) # type: ignore[attr-defined]

# Called when a new ResourceGroup changes its do-not-download status
def _resource_group_did_change_do_not_download(self, group: ResourceGroup) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_group_did_change_do_not_download'):
lis.resource_group_did_change_do_not_download(group) # type: ignore[attr-defined]

def _resource_group_will_forget(self, group: ResourceGroup) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_group_will_forget'):
lis.resource_group_will_forget(group) # type: ignore[attr-defined]

def _resource_group_did_forget(self, group: ResourceGroup) -> None:
# Notify normal listeners
for lis in self.listeners:
if hasattr(lis, 'resource_group_did_forget'):
lis.resource_group_did_forget(group) # type: ignore[attr-defined]

# === Close ===

def close(self) -> None:
Expand Down Expand Up @@ -3212,6 +3229,8 @@ def delete(self) -> None:
Deletes this resource group.
If it is referenced as a source, it will be replaced with None.
"""
self.project._resource_group_will_forget(self)

for rg in self.project.resource_groups:
if rg.source == self:
rg.source = None
Expand All @@ -3224,6 +3243,8 @@ def delete(self) -> None:
self._id = None # type: ignore[assignment] # intentionally leave exploding None

self.project._resource_groups.remove(self)

self.project._resource_group_did_forget(self)

# === Properties ===

Expand Down Expand Up @@ -3288,7 +3309,9 @@ def _set_source(self, value: ResourceGroupSource) -> None:

def _get_do_not_download(self) -> bool:
return self._do_not_download
def _set_do_not_download(self, value: bool) -> None:
# NOTE: The "save" parameter will be used to control whether the new value
# will be persisted, once persistence support for this option is added
def _set_do_not_download(self, value: bool, *, save: bool=True) -> None:
if self._do_not_download == value:
return
self._do_not_download = value
Expand Down
10 changes: 7 additions & 3 deletions src/crystal/tests/test_do_not_download_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,13 @@ async def test_then_embedded_resource_in_entity_tree_appears_with_do_not_downloa
await _assert_tree_item_icon_tooltip_contains(comic_image_r_ti, 'Ignored')

# Test: test_given_embedded_resource_also_in_a_non_do_not_download_group_then_embedded_resource_in_entity_tree_does_not_appear_with_do_not_download_badge
specific_comic_image_rg = ResourceGroup(
project, 'air_gap_2x.png', comic_image_r_url)
await _assert_tree_item_icon_tooltip_contains(comic_image_r_ti, 'Undownloaded')
if True:
specific_comic_image_rg = ResourceGroup(
project, 'air_gap_2x.png', comic_image_r_url)
await _assert_tree_item_icon_tooltip_contains(comic_image_r_ti, 'Undownloaded')

specific_comic_image_rg.delete()
await _assert_tree_item_icon_tooltip_contains(comic_image_r_ti, 'Ignored')


@skip('covered by: test_then_embedded_resource_in_entity_tree_appears_with_do_not_download_badge')
Expand Down

0 comments on commit 77ae84f

Please sign in to comment.