From ebdd3288f634d16ce084123356529d05b2dd3b95 Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Tue, 27 Aug 2024 19:41:59 -0300 Subject: [PATCH 1/7] Add a reversible mixin to invert sort order --- GTG/core/sorters.py | 112 +++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/GTG/core/sorters.py b/GTG/core/sorters.py index 47d58b96d..2d7cf1a03 100644 --- a/GTG/core/sorters.py +++ b/GTG/core/sorters.py @@ -31,14 +31,46 @@ def unwrap(row, expected_type): return item +class ReversibleSorter(Gtk.Sorter): + + def __init__(self) -> None: + self._reverse: bool = False + super().__init__() + + + @property + def reverse(self) -> bool: + return self._reverse -class TaskTitleSorter(Gtk.Sorter): - __gtype_name__ = 'TaskTitleSorter' - def __init__(self): - super(TaskTitleSorter, self).__init__() + @reverse.setter + def reverse(self, value: bool) -> None: + self._reverse = value + self.changed(Gtk.SorterChange.INVERTED) + def reversible_compare(self, first, second) -> Gtk.Ordering: + """Compare for reversible sorters.""" + + if self._reverse: + if first < second: + return Gtk.Ordering.LARGER + elif first > second: + return Gtk.Ordering.SMALLER + else: + return Gtk.Ordering.EQUAL + else: + if first > second: + return Gtk.Ordering.LARGER + elif first < second: + return Gtk.Ordering.SMALLER + else: + return Gtk.Ordering.EQUAL + + +class TaskTitleSorter(ReversibleSorter): + __gtype_name__ = 'TaskTitleSorter' + def do_compare(self, a, b) -> Gtk.Ordering: a = unwrap(a, Task) @@ -47,21 +79,12 @@ def do_compare(self, a, b) -> Gtk.Ordering: first = a.title[0] second = b.title[0] - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) -class TaskDueSorter(Gtk.Sorter): +class TaskDueSorter(ReversibleSorter): __gtype_name__ = 'DueSorter' - def __init__(self): - super(TaskDueSorter, self).__init__() - - def do_compare(self, a, b) -> Gtk.Ordering: a = unwrap(a, Task) @@ -70,21 +93,12 @@ def do_compare(self, a, b) -> Gtk.Ordering: first = a.date_due second = b.date_due - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) -class TaskStartSorter(Gtk.Sorter): +class TaskStartSorter(ReversibleSorter): __gtype_name__ = 'StartSorter' - def __init__(self): - super(TaskStartSorter, self).__init__() - - def do_compare(self, a, b) -> Gtk.Ordering: a = unwrap(a, Task) @@ -93,21 +107,12 @@ def do_compare(self, a, b) -> Gtk.Ordering: first = a.date_start second = b.date_start - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) -class TaskModifiedSorter(Gtk.Sorter): +class TaskModifiedSorter(ReversibleSorter): __gtype_name__ = 'ModifiedSorter' - def __init__(self): - super(TaskModifiedSorter, self).__init__() - - def do_compare(self, a, b) -> Gtk.Ordering: a = unwrap(a, Task) @@ -116,21 +121,12 @@ def do_compare(self, a, b) -> Gtk.Ordering: first = a.date_modified second = b.date_modified - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) -class TaskTagSorter(Gtk.Sorter): +class TaskTagSorter(ReversibleSorter): __gtype_name__ = 'TagSorter' - def __init__(self): - super(TaskTagSorter, self).__init__() - - def get_first_letter(self, tags) -> str: """Get first letter of the first tag in a set of tags.""" @@ -154,21 +150,12 @@ def do_compare(self, a, b) -> Gtk.Ordering: else: second = 'zzzzzzz' - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) -class TaskAddedSorter(Gtk.Sorter): +class TaskAddedSorter(ReversibleSorter): __gtype_name__ = 'AddedSorter' - def __init__(self): - super(TaskAddedSorter, self).__init__() - - def do_compare(self, a, b) -> Gtk.Ordering: a = unwrap(a, Task) @@ -177,9 +164,4 @@ def do_compare(self, a, b) -> Gtk.Ordering: first = a.date_added second = b.date_added - if first > second: - return Gtk.Ordering.LARGER - elif first < second: - return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + return self.reversible_compare(first, second) From 7b133abecb099edc4b226a52e19bf6f7a9d962a9 Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Tue, 27 Aug 2024 20:00:45 -0300 Subject: [PATCH 2/7] Add actions to change sort order --- GTG/gtk/browser/main_window.py | 14 ++++++++++++++ GTG/gtk/browser/task_pane.py | 7 +++++++ GTG/gtk/data/main_window.ui | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/GTG/gtk/browser/main_window.py b/GTG/gtk/browser/main_window.py index 01e3b069e..4d7d1b265 100644 --- a/GTG/gtk/browser/main_window.py +++ b/GTG/gtk/browser/main_window.py @@ -248,6 +248,8 @@ def _set_actions(self): ('sort_by_modified', self.on_sort_modified, None), ('sort_by_added', self.on_sort_added, None), ('sort_by_tags', self.on_sort_tags, None), + ('sort_asc', self.on_sort_order_asc, None), + ('sort_desc', self.on_sort_order_desc, None), ] for action, callback, accel in action_entries: @@ -1342,6 +1344,18 @@ def store_sorting(self, mode: str) -> None: self.config.set('sort_mode_open', mode) + def on_sort_order_asc(self, action, params) -> None: + """Set ascending order for current sorter.""" + + self.get_pane().set_sort_order(reverse=False) + + + def on_sort_order_desc(self, action, params) -> None: + """Set descending order for current sorter.""" + + self.get_pane().set_sort_order(reverse=True) + + def set_sorter(self, value: str) -> None: """Set sorter for current task pane.""" diff --git a/GTG/gtk/browser/task_pane.py b/GTG/gtk/browser/task_pane.py index 1dce6f414..58767af7d 100644 --- a/GTG/gtk/browser/task_pane.py +++ b/GTG/gtk/browser/task_pane.py @@ -165,6 +165,7 @@ def __init__(self, browser, pane): self.filtered.set_filter(self.task_filter) self.sort_model = Gtk.TreeListRowSorter() + self.sort_model.set_sorter(TaskTitleSorter()) self.main_sorter = Gtk.SortListModel() self.main_sorter.set_model(self.filtered) @@ -305,6 +306,12 @@ def set_sorter(self, method=None) -> None: self.sort_model.set_sorter(sorter) + def set_sort_order(self, reverse: bool) -> None: + """Set order for the sorter.""" + + self.sort_model.get_sorter().reverse = reverse + + def on_listview_activated(self, listview, position, user_data = None): """Callback when double clicking on a row.""" diff --git a/GTG/gtk/data/main_window.ui b/GTG/gtk/data/main_window.ui index 251b8a0b0..35af18718 100644 --- a/GTG/gtk/data/main_window.ui +++ b/GTG/gtk/data/main_window.ui @@ -226,6 +226,14 @@ Sort by Tags win.sort_by_tags + + Ascending Order + win.sort_asc + + + Descending Order + win.sort_desc + From d357e5e562ed3c78c7998d7cf7dbdff1a2ae25df Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Tue, 27 Aug 2024 20:07:15 -0300 Subject: [PATCH 3/7] Add sections to sort menu --- GTG/gtk/data/main_window.ui | 69 ++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/GTG/gtk/data/main_window.ui b/GTG/gtk/data/main_window.ui index 35af18718..433d597ee 100644 --- a/GTG/gtk/data/main_window.ui +++ b/GTG/gtk/data/main_window.ui @@ -197,43 +197,48 @@ - - Sort by Title - win.sort_by_title - +
+ + Sort by Title + win.sort_by_title + + + + Sort by Start Date + win.sort_by_start + - - Sort by Start Date - win.sort_by_start - + + Sort by Due Date + win.sort_by_due + - - Sort by Due Date - win.sort_by_due - + + Sort by Added Date + win.sort_by_added + - - Sort by Added Date - win.sort_by_added - + + Sort by Modified Date + win.sort_by_modified + - - Sort by Modified Date - win.sort_by_modified - + + Sort by Tags + win.sort_by_tags + +
- - Sort by Tags - win.sort_by_tags - - - Ascending Order - win.sort_asc - - - Descending Order - win.sort_desc - +
+ + Ascending Order + win.sort_asc + + + Descending Order + win.sort_desc + +
From 79ab4153ad2adb05cf76b9b2b8f975d7f8fafa12 Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Mon, 9 Sep 2024 15:22:31 -0300 Subject: [PATCH 4/7] Change icon according to sort order --- GTG/gtk/browser/main_window.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/GTG/gtk/browser/main_window.py b/GTG/gtk/browser/main_window.py index 4d7d1b265..83e1283e4 100644 --- a/GTG/gtk/browser/main_window.py +++ b/GTG/gtk/browser/main_window.py @@ -94,6 +94,8 @@ class MainWindow(Gtk.ApplicationWindow): defer_menu_btn = Gtk.Template.Child() defer_menu_days_section = Gtk.Template.Child() + sort_btn = Gtk.Template.Child('sort_menu_btn') + headerbar = Gtk.Template.Child('browser_headerbar') main_menu_btn = Gtk.Template.Child() main_menu = Gtk.Template.Child() @@ -1348,12 +1350,14 @@ def on_sort_order_asc(self, action, params) -> None: """Set ascending order for current sorter.""" self.get_pane().set_sort_order(reverse=False) + self.change_sort_icon('ASC') def on_sort_order_desc(self, action, params) -> None: """Set descending order for current sorter.""" self.get_pane().set_sort_order(reverse=True) + self.change_sort_icon('DESC') def set_sorter(self, value: str) -> None: @@ -1362,6 +1366,15 @@ def set_sorter(self, value: str) -> None: self.get_pane().set_sorter(value) + def change_sort_icon(self, order: str) -> None: + """Change icon for sorting menu button.""" + + if order == 'ASC': + self.sort_btn.set_icon_name('view-sort-ascending-symbolic') + elif order == 'DESC': + self.sort_btn.set_icon_name('view-sort-descending-symbolic') + + def close_all_task_editors(self, task_id): """ Including editors of subtasks """ all_subtasks = [] From b38bc0fb27e2ad22fea83786f43a74ebb83c90b0 Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Sat, 14 Sep 2024 18:56:09 -0300 Subject: [PATCH 5/7] Use stateful actions for sorting --- GTG/gtk/browser/main_window.py | 63 +++++++++------------------------- GTG/gtk/data/main_window.ui | 18 ++++++---- 2 files changed, 29 insertions(+), 52 deletions(-) diff --git a/GTG/gtk/browser/main_window.py b/GTG/gtk/browser/main_window.py index 83e1283e4..13500793d 100644 --- a/GTG/gtk/browser/main_window.py +++ b/GTG/gtk/browser/main_window.py @@ -243,13 +243,6 @@ def _set_actions(self): ('recurring_month', self.on_set_recurring_every_month, None), ('recurring_year', self.on_set_recurring_every_year, None), ('recurring_toggle', self.on_toggle_recurring, None), - ('sort_by_start', self.on_sort_start, None), - ('sort_by_due', self.on_sort_due, None), - ('sort_by_added', self.on_sort_added, None), - ('sort_by_title', self.on_sort_title, None), - ('sort_by_modified', self.on_sort_modified, None), - ('sort_by_added', self.on_sort_added, None), - ('sort_by_tags', self.on_sort_tags, None), ('sort_asc', self.on_sort_order_asc, None), ('sort_desc', self.on_sort_order_desc, None), ] @@ -264,6 +257,17 @@ def _set_actions(self): if accel is not None: self.app.set_accels_for_action(*accel) + + + # Stateful actions from now on + sort_variant = GLib.Variant.new_string('Title') + sort_action = Gio.SimpleAction.new_stateful('sort', + sort_variant.get_type(), + sort_variant) + + sort_action.connect('change-state', self.on_sort) + self.add_action(sort_action) + def _init_icon_theme(self): """ @@ -1292,46 +1296,13 @@ def on_modify_tags(self, action, params): self.modifytags_dialog.modify_tags(tasks) - def on_sort_start(self, action, params) -> None: - """Callback when changing task sorting.""" - - self.set_sorter('Start') - self.store_sorting('start') - - - def on_sort_due(self, action, params) -> None: - """Callback when changing task sorting.""" - - self.set_sorter('Due') - self.store_sorting('due') - - - def on_sort_added(self, action, params) -> None: - """Callback when changing task sorting.""" - - self.set_sorter('Added') - self.store_sorting('added') - - - def on_sort_title(self, action, params) -> None: - """Callback when changing task sorting.""" - - self.set_sorter('Title') - self.store_sorting('title') - - - def on_sort_modified(self, action, params) -> None: - """Callback when changing task sorting.""" - - self.set_sorter('Modified') - self.store_sorting('modified') - - - def on_sort_tags(self, action, params) -> None: - """Callback when changing task sorting.""" + def on_sort(self, action, value) -> None: + + action.set_state(value) + value_str = value.get_string() - self.set_sorter('Tags') - self.store_sorting('tags') + self.set_sorter(value_str) + self.store_sorting(value_str.lower()) def store_sorting(self, mode: str) -> None: diff --git a/GTG/gtk/data/main_window.ui b/GTG/gtk/data/main_window.ui index 433d597ee..780efdf6e 100644 --- a/GTG/gtk/data/main_window.ui +++ b/GTG/gtk/data/main_window.ui @@ -200,32 +200,38 @@
Sort by Title - win.sort_by_title + Title + win.sort Sort by Start Date - win.sort_by_start + Start + win.sort Sort by Due Date - win.sort_by_due + Due + win.sort Sort by Added Date - win.sort_by_added + Added + win.sort Sort by Modified Date - win.sort_by_modified + Modified + win.sort Sort by Tags - win.sort_by_tags + Tags + win.sort
From 1b2ea286f7ee924804ce61051094b733c506d2c1 Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Sat, 14 Sep 2024 19:08:26 -0300 Subject: [PATCH 6/7] Use stateful actions for sorting order --- GTG/gtk/browser/main_window.py | 37 +++++++++++++++++++--------------- GTG/gtk/data/main_window.ui | 6 ++++-- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/GTG/gtk/browser/main_window.py b/GTG/gtk/browser/main_window.py index 13500793d..74244452c 100644 --- a/GTG/gtk/browser/main_window.py +++ b/GTG/gtk/browser/main_window.py @@ -243,8 +243,6 @@ def _set_actions(self): ('recurring_month', self.on_set_recurring_every_month, None), ('recurring_year', self.on_set_recurring_every_year, None), ('recurring_toggle', self.on_toggle_recurring, None), - ('sort_asc', self.on_sort_order_asc, None), - ('sort_desc', self.on_sort_order_desc, None), ] for action, callback, accel in action_entries: @@ -268,6 +266,14 @@ def _set_actions(self): sort_action.connect('change-state', self.on_sort) self.add_action(sort_action) + order_variant = GLib.Variant.new_string('ASC') + order_action = Gio.SimpleAction.new_stateful('sort_order', + order_variant.get_type(), + order_variant) + + order_action.connect('change-state', self.on_sort_order) + self.add_action(order_action) + def _init_icon_theme(self): """ @@ -1305,6 +1311,19 @@ def on_sort(self, action, value) -> None: self.store_sorting(value_str.lower()) + def on_sort_order(self, action, value) -> None: + + action.set_state(value) + value_str = value.get_string() + + if value_str == 'ASC': + self.get_pane().set_sort_order(reverse=False) + self.change_sort_icon('ASC') + else: + self.get_pane().set_sort_order(reverse=True) + self.change_sort_icon('DESC') + + def store_sorting(self, mode: str) -> None: """Store sorting mode.""" @@ -1317,20 +1336,6 @@ def store_sorting(self, mode: str) -> None: self.config.set('sort_mode_open', mode) - def on_sort_order_asc(self, action, params) -> None: - """Set ascending order for current sorter.""" - - self.get_pane().set_sort_order(reverse=False) - self.change_sort_icon('ASC') - - - def on_sort_order_desc(self, action, params) -> None: - """Set descending order for current sorter.""" - - self.get_pane().set_sort_order(reverse=True) - self.change_sort_icon('DESC') - - def set_sorter(self, value: str) -> None: """Set sorter for current task pane.""" diff --git a/GTG/gtk/data/main_window.ui b/GTG/gtk/data/main_window.ui index 780efdf6e..2831460ce 100644 --- a/GTG/gtk/data/main_window.ui +++ b/GTG/gtk/data/main_window.ui @@ -238,11 +238,13 @@
Ascending Order - win.sort_asc + ASC + win.sort_order Descending Order - win.sort_desc + DESC + win.sort_order
From bd87ecdd88e9a161683c29c21c9912131292895a Mon Sep 17 00:00:00 2001 From: Diego Garcia Gangl Date: Sat, 14 Sep 2024 23:05:37 -0300 Subject: [PATCH 7/7] Simplify code for reversible sorter Thanks to @SqAtx for the suggestion --- GTG/core/sorters.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/GTG/core/sorters.py b/GTG/core/sorters.py index 2d7cf1a03..ef77cdd8b 100644 --- a/GTG/core/sorters.py +++ b/GTG/core/sorters.py @@ -52,20 +52,19 @@ def reverse(self, value: bool) -> None: def reversible_compare(self, first, second) -> Gtk.Ordering: """Compare for reversible sorters.""" - if self._reverse: - if first < second: + if first == second: + return Gtk.Ordering.EQUAL + + if first < second: + if self._reverse: return Gtk.Ordering.LARGER - elif first > second: - return Gtk.Ordering.SMALLER else: - return Gtk.Ordering.EQUAL - else: - if first > second: - return Gtk.Ordering.LARGER - elif first < second: return Gtk.Ordering.SMALLER - else: - return Gtk.Ordering.EQUAL + + if self._reverse: + return Gtk.Ordering.SMALLER + else: + return Gtk.Ordering.LARGER class TaskTitleSorter(ReversibleSorter):