diff --git a/GTG/core/tasks.py b/GTG/core/tasks.py index 3f05287a7..f527e3b10 100644 --- a/GTG/core/tasks.py +++ b/GTG/core/tasks.py @@ -699,6 +699,7 @@ def __init__(self) -> None: self.model = Gio.ListStore.new(Task) self.tree_model = Gtk.TreeListModel.new(self.model, False, False, self.model_expand) + self.tid_to_subtask_model = dict() def model_expand(self, item): @@ -712,6 +713,7 @@ def model_expand(self, item): for child in item.children: model.append(child) + self.tid_to_subtask_model[item.id] = model return Gtk.TreeListModel.new(model, False, False, self.model_expand) @@ -893,6 +895,37 @@ def to_xml(self) -> Element: return root + + def _remove_from_parent_model(self,task_id: UUID) -> None: + """ + Remove the task indicated by task_id from the model of its parent's subtasks. + This is required to trigger a GUI update. + """ + item = self.lookup[task_id] + if item.parent is None: + return + if item.parent.id not in self.tid_to_subtask_model: + return + model = self.tid_to_subtask_model[item.parent.id] + pos = model.find(item) + if pos[0]: model.remove(pos[1]) + + + def _append_to_parent_model(self,task_id: UUID) -> None: + """ + Appends the task indicated by task_id to the model of its parent's subtasks. + This is required to trigger a GUI update. + """ + item = self.lookup[task_id] + if item.parent is None: + return + if item.parent.id not in self.tid_to_subtask_model: + return + model = self.tid_to_subtask_model[item.parent.id] + pos = model.find(item) + if not pos[0]: model.append(item) + + def add(self, item: Any, parent_id: UUID = None) -> None: """Add a task to the taskstore.""" @@ -900,6 +933,9 @@ def add(self, item: Any, parent_id: UUID = None) -> None: if not parent_id: self.model.append(item) + else: + self._append_to_parent_model(item.id) + self.lookup[parent_id].notify('has_children') item.duplicate_cb = self.duplicate_for_recurrent self.notify('task_count_all') @@ -913,8 +949,12 @@ def remove(self, item_id: UUID) -> None: # Remove from UI item = self.lookup[item_id] - pos = self.model.find(item) - self.model.remove(pos[1]) + if item.parent is not None: + self._remove_from_parent_model(item.id) + item.parent.notify('has_children') + else: + pos = self.model.find(item) + self.model.remove(pos[1]) super().remove(item_id) @@ -924,23 +964,38 @@ def remove(self, item_id: UUID) -> None: def parent(self, item_id: UUID, parent_id: UUID) -> None: - super().parent(item_id, parent_id) + item = self.lookup[item_id] # Remove from UI - item = self.lookup[item_id] - pos = self.model.find(item) - self.model.remove(pos[1]) + if item.parent is not None: + self._remove_from_parent_model(item_id) + item.parent.notify('has_children') + else: + pos = self.model.find(item) + self.model.remove(pos[1]) + + super().parent(item_id, parent_id) + + # Add back to UI + self._append_to_parent_model(item_id) + item.parent.notify('has_children') def unparent(self, item_id: UUID, parent_id: UUID) -> None: - super().unparent(item_id, parent_id) item = self.lookup[item_id] parent = self.lookup[parent_id] + # Remove from UI + self._remove_from_parent_model(item_id) + item.parent.notify('has_children') + + super().unparent(item_id, parent_id) + # remove inline references to the former subtask parent.content = re.sub(r'\{\!\s*'+str(item_id)+r'\s*\!\}','',parent.content) + # Add back to UI self.model.append(item) parent.notify('has_children') diff --git a/GTG/gtk/browser/task_pane.py b/GTG/gtk/browser/task_pane.py index 9e3924fec..ff23ed92d 100644 --- a/GTG/gtk/browser/task_pane.py +++ b/GTG/gtk/browser/task_pane.py @@ -629,8 +629,6 @@ def drag_drop(self, target, task, x, y): self.ds.tasks.parent(task.id, dropped.id) self.refresh() - self.emit('collapse-all') - self.emit('expand-all') def on_task_RMB_click(self, gesture, sequence) -> None: @@ -664,11 +662,6 @@ def on_toplevel_tag_drop(self, drop_target, task, x, y): self.ds.tasks.tree_model.emit('items-changed', 0, 0, 0) self.refresh() - # Not pretty, but needed to force the update of - # the parent task and it's remaining children - self.emit('collapse-all') - self.emit('expand-all') - return True else: return False