diff --git a/GTG/core/datastore.py b/GTG/core/datastore.py index df88580e4..b4a14b419 100644 --- a/GTG/core/datastore.py +++ b/GTG/core/datastore.py @@ -222,7 +222,7 @@ def count_tasks(count: dict, tasklist: list): if not task.tags: count['untagged'] += 1 - for tag in task.tags: + for tag in { t for owned_tag in task.tags for t in [owned_tag] + owned_tag.get_ancestors() }: val = count.get(tag.name, 0) count[tag.name] = val + 1 @@ -246,6 +246,17 @@ def count_tasks(count: dict, tasklist: list): self.tasks.filter(Filter.ACTIONABLE)) + def refresh_tag_stats(self) -> None: + """ + Refresh the number of tasks for each tag. + """ + self.refresh_task_count() + for tag_name in self.tags.get_all_tag_names(): + tag = self.tags.find(tag_name) + self.refresh_task_for_tag(tag) + self.notify_tag_change(tag) + + def notify_tag_change(self, tag) -> None: """Notify tasks that this tag has changed.""" diff --git a/GTG/core/tags.py b/GTG/core/tags.py index 4b7b64571..71f0afb68 100644 --- a/GTG/core/tags.py +++ b/GTG/core/tags.py @@ -27,7 +27,7 @@ import re from lxml.etree import Element, SubElement -from typing import Any, Dict, Set +from typing import Any, Dict, List, Set from GTG.core.base_store import BaseStore @@ -163,6 +163,15 @@ def set_task_count_closed(self, value: int) -> None: self._task_count_closed = value + def get_ancestors(self) -> List['Tag']: + """Return all ancestors of this tag""" + ancestors = [] + here = self + while here.parent: + here = here.parent + ancestors.append(here) + return ancestors + def __hash__(self): return id(self) @@ -207,6 +216,10 @@ def __str__(self) -> str: return f'Tag Store. Holds {len(self.lookup)} tag(s)' + def get_all_tag_names(self) -> List[str]: + """Return all tag names.""" + return list(self.lookup_names.keys()) + def find(self, name: str) -> Tag: """Get a tag by name.""" diff --git a/GTG/gtk/browser/sidebar.py b/GTG/gtk/browser/sidebar.py index d6d781e71..78c166a2c 100644 --- a/GTG/gtk/browser/sidebar.py +++ b/GTG/gtk/browser/sidebar.py @@ -586,7 +586,6 @@ def check_parent(self, value, target) -> bool: def drag_drop(self, target, value, x, y): """Callback when dropping onto a target""" - dropped = target.get_widget().props.tag if not self.check_parent(value, dropped): @@ -596,7 +595,10 @@ def drag_drop(self, target, value, x, y): self.ds.tags.unparent(value.id, value.parent.id) self.ds.tags.parent(value.id, dropped.id) + self.ds.refresh_tag_stats() self.ds.tags.tree_model.emit('items-changed', 0, 0, 0) + self.refresh_tags() + def drop_enter(self, target, x, y, user_data=None): @@ -646,7 +648,8 @@ def notify_task(self, task: Task) -> None: def on_toplevel_tag_drop(self, drop_target, tag, x, y): if tag.parent: self.ds.tags.unparent(tag.id, tag.parent.id) - + self.ds.refresh_tag_stats() + self.refresh_tags() try: for expander in self.expanders: expander.activate_action('listitem.toggle-expand')