diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index fcf01f4e4..884a18539 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -46,4 +46,5 @@ jobs: - name: Run unit tests with Pytest run: | export PYTHONPATH=${PWD}/inst/lib/python3.9/site-packages - pytest + # Provide a fake display server, for tests that need one + xvfb-run pytest diff --git a/GTG/core/tasks.py b/GTG/core/tasks.py index 32e3afd97..18c563601 100644 --- a/GTG/core/tasks.py +++ b/GTG/core/tasks.py @@ -295,6 +295,10 @@ def date_modified(self, value: Any) -> None: self._date_modified = Date(value) + def is_new(self) -> bool: + return self.title == DEFAULT_TITLE and not self.content + + @GObject.Property(type=str) def title(self) -> str: return self.raw_title @@ -753,7 +757,7 @@ def duplicate_for_recurrent(self, task: Task) -> Task: return new_task - def new(self, title: str = None, parent: Optional[UUID] = None) -> Task: + def new(self, title: str = '', parent: Optional[UUID] = None) -> Task: """Create a new task and add it to the store.""" tid = uuid4() diff --git a/GTG/gtk/editor/editor.py b/GTG/gtk/editor/editor.py index f26707166..39c94051d 100644 --- a/GTG/gtk/editor/editor.py +++ b/GTG/gtk/editor/editor.py @@ -39,7 +39,7 @@ from GTG.gtk.editor.recurring_menu import RecurringMenu from GTG.gtk.editor.taskview import TaskView from GTG.gtk.colors import rgb_to_hex -from GTG.core.tasks import Task, Status, DEFAULT_TITLE +from GTG.core.tasks import Task, Status log = logging.getLogger(__name__) @@ -148,21 +148,9 @@ def __init__(self, app, task): provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ) - # self.textview.browse_tag_cb = app.select_tag - # self.textview.new_subtask_cb = self.new_subtask - # self.textview.get_subtasks_cb = task.get_children - # self.textview.delete_subtask_cb = self.remove_subtask - # self.textview.rename_subtask_cb = self.rename_subtask - # self.textview.open_subtask_cb = self.open_subtask - # self.textview.save_cb = self.light_save - # self.textview.add_tasktag_cb = self.tag_added - # self.textview.remove_tasktag_cb = self.tag_removed - # self.textview.refresh_cb = self.refresh_editor - # self.textview.get_tagslist_cb = task.get_tags_name - # self.textview.tid = task.id - self.textview.browse_tag_cb = app.select_tag self.textview.new_subtask_cb = self.new_subtask + # self.textview.get_subtasks_cb = task.get_children self.textview.delete_subtask_cb = self.remove_subtask self.textview.rename_subtask_cb = self.rename_subtask self.textview.open_subtask_cb = self.open_subtask @@ -170,6 +158,7 @@ def __init__(self, app, task): self.textview.add_tasktag_cb = self.tag_added self.textview.remove_tasktag_cb = self.tag_removed self.textview.refresh_cb = self.refresh_editor + # self.textview.get_tagslist_cb = task.get_tags_name self.textview.tid = task.id # Voila! it's done @@ -178,40 +167,7 @@ def __init__(self, app, task): textview_focus_controller.connect("leave", self.on_textview_focus_out) self.textview.add_controller(textview_focus_controller) - tags = task.tags - text = self.task.content - title = self.task.title - - # Insert text and tags as a non_undoable action, otherwise - # the user can CTRL+Z even this inserts. - self.textview.buffer.begin_irreversible_action() - self.textview.buffer.set_text(f"{title}\n") - - if text: - self.textview.insert(text) - - # Insert any remaining tags - if tags: - tag_names = [t.name for t in tags] - self.textview.insert_tags(tag_names) - else: - # If not text, we insert tags - if tags: - tag_names = [t.name for t in tags] - self.textview.insert_tags(tag_names) - start = self.textview.buffer.get_end_iter() - self.textview.buffer.insert(start, '\n') - - # Insert subtasks if they weren't inserted in the text - subtasks = task.children - for sub in subtasks: - if sub.id not in self.textview.subtasks['tags']: - self.textview.insert_existing_subtask(sub) - - if self.is_new(): - self.textview.select_title() - - self.textview.buffer.end_irreversible_action() + self.textview.set_text_from_task() # Connect search field to tags popup self.tags_tree.set_search_entry(self.tags_entry) @@ -872,8 +828,7 @@ def on_window_focus_change(self, window, gparam): def is_new(self) -> bool: - return (self.task.title == DEFAULT_TITLE - and self.textview.get_text() == '') + return self.task.is_new() def destruction(self, _=None): diff --git a/GTG/gtk/editor/taskview.py b/GTG/gtk/editor/taskview.py index 9bbf91d1e..27e36e6a5 100644 --- a/GTG/gtk/editor/taskview.py +++ b/GTG/gtk/editor/taskview.py @@ -165,6 +165,38 @@ def __init__(self, ds: Datastore, task, clipboard, dark) -> None: press_gesture.connect('begin', self.on_single_begin) self.add_controller(press_gesture) + def set_text_from_task(self) -> None: + """Sets the text of the view, from the text of the task""" + # Insert text and tags as a non_undoable action, otherwise + # the user can CTRL+Z even this inserts. + self.buffer.begin_irreversible_action() + self.buffer.set_text(f"{self.task.title}\n") + + if self.task.content: + self.insert(self.task.content) + + # Insert any remaining tags + if self.task.tags: + tag_names = [t.name for t in self.task.tags] + self.insert_tags(tag_names) + else: + # If not text, we insert tags + if self.task.tags: + tag_names = [t.name for t in self.task.tags] + self.insert_tags(tag_names) + start = self.buffer.get_end_iter() + self.buffer.insert(start, '\n') + + # Insert subtasks if they weren't inserted in the text + subtasks = self.task.children + for sub in subtasks: + if sub.id not in self.subtasks['tags']: + self.insert_existing_subtask(sub) + + if self.task.is_new(): + self.select_title() + + self.buffer.end_irreversible_action() def on_modified(self, buffer: Gtk.TextBuffer) -> None: """Called every time the text buffer changes.""" diff --git a/tests/core/test_task.py b/tests/core/test_task.py index ddf8c46fc..5db341931 100644 --- a/tests/core/test_task.py +++ b/tests/core/test_task.py @@ -28,6 +28,22 @@ class TestTask(TestCase): + def test_default_task_from_store_is_new(self): + task = TaskStore().new() + + self.assertTrue(task.is_new()) + + def test_task_with_content_is_not_new(self): + task = TaskStore().new() + task.content = 'foobar' + + self.assertFalse(task.is_new()) + + def test_task_with_title_is_not_new(self): + task = TaskStore().new(title='My new task') + + self.assertFalse(task.is_new()) + def test_title(self): task = Task(id=uuid4(), title='\tMy Title\n') diff --git a/tests/core/test_taskview.py b/tests/core/test_taskview.py index 41611d613..bf7b4b947 100644 --- a/tests/core/test_taskview.py +++ b/tests/core/test_taskview.py @@ -16,9 +16,14 @@ # this program. If not, see . # ----------------------------------------------------------------------------- +import os +import pytest import re +from uuid import uuid4 from unittest import TestCase -from GTG.gtk.editor.taskview import TAG_REGEX +from GTG.core.datastore import Datastore +from GTG.core.tasks import Task +from GTG.gtk.editor.taskview import TaskView, TAG_REGEX class TestTaskView(TestCase): @@ -41,3 +46,15 @@ def test_no_detect_tags(self): matches = re.findall(TAG_REGEX, content) self.assertEqual([], matches) + + def test_get_title(self): + task_title = 'Very important task' + task = Task(id = uuid4(), title=task_title) + view = TaskView(Datastore(), task, None, False) + view.refresh_cb = lambda x: x # Refresh CB that does nothing + view.set_text_from_task() + view.detect_title() + + view_title = view.get_title() + + self.assertEqual(view_title, task_title)