[geary/wip/713872-filtering] Squashed commit of the following:
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/713872-filtering] Squashed commit of the following:
- Date: Tue, 21 Oct 2014 20:42:01 +0000 (UTC)
commit 3ec1f6dfcc3169f960e97df60dbce01d59c6f2ba
Author: Private <geek vigilante gmail com>
Date: Tue Oct 21 13:40:48 2014 -0700
Squashed commit of the following:
commit 2a17916d8c0afa06b8cac91c800c5f699fa540dd
Author: Private <geek vigilante gmail com>
Date: Sun Oct 12 22:39:09 2014 +0200
Completed message filter.
commit 904f81b8873ab535711d001df30d2943d520d458
Author: Private <geek vigilante gmail com>
Date: Sun Sep 28 10:02:05 2014 +0200
Added option for folder filtering by unread and starred messages.
From https://github.com/geekvigilante/geary
po/POTFILES.in | 1 +
src/CMakeLists.txt | 1 +
src/client/application/geary-controller.vala | 75 +++++++++++++++
src/client/components/main-toolbar.vala | 10 ++
src/client/components/main-window.vala | 5 +-
.../conversation-list/conversation-filter.vala | 100 ++++++++++++++++++++
.../conversation-list/conversation-list-store.vala | 16 ---
.../conversation-list/conversation-list-view.vala | 29 +++---
ui/CMakeLists.txt | 1 +
ui/toolbar_filter_menu.ui | 9 ++
10 files changed, 216 insertions(+), 31 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 77f2fec..07a3825 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -365,5 +365,6 @@ src/engine/util/util-trillian.vala
[type: gettext/glade]ui/preferences.glade
[type: gettext/glade]ui/remove_confirm.glade
[type: gettext/glade]ui/toolbar_mark_menu.ui
+[type: gettext/glade]ui/toolbar_filter_menu.ui
[type: gettext/glade]ui/toolbar_menu.ui
[type: gettext/glade]ui/upgrade_dialog.glade
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5579bcb..e8ce45b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -337,6 +337,7 @@ client/composer/email-entry.vala
client/composer/scrollable-overlay.vala
client/composer/webview-edit-fixer.vala
+client/conversation-list/conversation-filter.vala
client/conversation-list/conversation-list-cell-renderer.vala
client/conversation-list/conversation-list-store.vala
client/conversation-list/conversation-list-view.vala
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index c53fb67..73bb569 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -46,6 +46,10 @@ public class GearyController : Geary.BaseObject {
public const string ACTION_MARK_AS_SPAM = "GearyMarkAsSpam";
public const string ACTION_COPY_MENU = "GearyCopyMenuButton";
public const string ACTION_MOVE_MENU = "GearyMoveMenuButton";
+ public const string ACTION_FILTER_MENU = "GearyFilterMenuButton";
+ public const string ACTION_FILTER_SHOW_ALL = "GearyFilterShowAll";
+ public const string ACTION_FILTER_SHOW_UNREAD = "GearyFilterShowUnread";
+ public const string ACTION_FILTER_SHOW_STARRED = "GearyFilterShowStarred";
public const string ACTION_GEAR_MENU = "GearyGearMenuButton";
public const string ACTION_SEARCH = "GearySearch";
@@ -334,6 +338,11 @@ public class GearyController : Geary.BaseObject {
Gtk.ActionEntry move_menu = { ACTION_MOVE_MENU, null, TRANSLATABLE, "M", _("Move conversation"),
null };
move_menu.label = _("_Move");
entries += move_menu;
+
+ Gtk.ActionEntry filter_menu = { ACTION_FILTER_MENU, null, TRANSLATABLE, null, _("Filter messages"),
+ null };
+ filter_menu.label = _("_Filter");
+ entries += filter_menu;
Gtk.ActionEntry new_message = { ACTION_NEW_MESSAGE, null, null, "<Ctrl>N",
_("Compose new message (Ctrl+N, N)"), on_new_message };
@@ -419,6 +428,21 @@ public class GearyController : Geary.BaseObject {
null, null, false };
entries += gear_menu;
+ Gtk.ToggleActionEntry filter_show_all = { ACTION_FILTER_SHOW_ALL, "filter-show-all", TRANSLATABLE,
null,
+ null, on_filter_show_all, true };
+ filter_show_all.label = _("Show _All Messages");
+ entries += filter_show_all;
+
+ Gtk.ToggleActionEntry filter_show_unread = { ACTION_FILTER_SHOW_UNREAD, "filter-show-unread",
+ TRANSLATABLE, null, null, on_filter_show_unread, false };
+ filter_show_unread.label = _("Only _Unread Messages");
+ entries += filter_show_unread;
+
+ Gtk.ToggleActionEntry filter_show_starred = { ACTION_FILTER_SHOW_STARRED, "filter-show-starred",
+ TRANSLATABLE, null, null, on_filter_show_starred, false };
+ filter_show_starred.label = _("Only _Starred Messages");
+ entries += filter_show_starred;
+
return entries;
}
@@ -1332,6 +1356,10 @@ public class GearyController : Geary.BaseObject {
select_folder_mutex.release(ref mutex_token);
+ Gtk.ActionGroup actions = GearyApplication.instance.actions;
+ Gtk.ToggleAction show_all_action = actions.get_action(ACTION_FILTER_SHOW_ALL) as Gtk.ToggleAction;
+ show_all_action.set_active(true);
+
debug("Switched to %s", folder.to_string());
}
@@ -1824,6 +1852,53 @@ public class GearyController : Geary.BaseObject {
mark_as_spam_async.begin(null);
}
+ private void on_filter_show_all() {
+ Gtk.ActionGroup actions = GearyApplication.instance.actions;
+
+ Gtk.ToggleAction show_all_action = actions.get_action(ACTION_FILTER_SHOW_ALL) as Gtk.ToggleAction;
+ Gtk.ToggleAction show_unread_action = actions.get_action(ACTION_FILTER_SHOW_UNREAD) as
Gtk.ToggleAction;
+ Gtk.ToggleAction show_starred_action = actions.get_action(ACTION_FILTER_SHOW_STARRED) as
Gtk.ToggleAction;
+
+ if (show_unread_action.active || show_starred_action.active) {
+ if (show_all_action.active) {
+ show_unread_action.active = false;
+ show_starred_action.active = false;
+ }
+ } else {
+ show_all_action.active = true;
+ }
+ }
+
+ private void on_filter_show_unread() {
+ Gtk.ActionGroup actions = GearyApplication.instance.actions;
+
+ Gtk.ToggleAction show_all_action = actions.get_action(ACTION_FILTER_SHOW_ALL) as Gtk.ToggleAction;
+ Gtk.ToggleAction show_unread_action = actions.get_action(ACTION_FILTER_SHOW_UNREAD) as
Gtk.ToggleAction;
+ Gtk.ToggleAction show_starred_action = actions.get_action(ACTION_FILTER_SHOW_STARRED) as
Gtk.ToggleAction;
+
+ if (show_unread_action.active)
+ show_all_action.active = false;
+ else if (!show_starred_action.active)
+ show_all_action.active = true;
+
+ main_window.conversation_filter.set_unread_filter(show_unread_action.active);
+ }
+
+ private void on_filter_show_starred() {
+ Gtk.ActionGroup actions = GearyApplication.instance.actions;
+
+ Gtk.ToggleAction show_all_action = actions.get_action(ACTION_FILTER_SHOW_ALL) as Gtk.ToggleAction;
+ Gtk.ToggleAction show_unread_action = actions.get_action(ACTION_FILTER_SHOW_UNREAD) as
Gtk.ToggleAction;
+ Gtk.ToggleAction show_starred_action = actions.get_action(ACTION_FILTER_SHOW_STARRED) as
Gtk.ToggleAction;
+
+ if (show_starred_action.active)
+ show_all_action.active = false;
+ else if (!show_unread_action.active)
+ show_all_action.active = true;
+
+ main_window.conversation_filter.set_starred_filter(show_starred_action.active);
+ }
+
private void copy_email(Gee.Collection<Geary.EmailIdentifier> ids,
Geary.FolderPath destination) {
if (ids.size > 0) {
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
index 7e8d442..9969717 100644
--- a/src/client/components/main-toolbar.vala
+++ b/src/client/components/main-toolbar.vala
@@ -35,6 +35,11 @@ public class MainToolbar : PillHeaderbar {
Gtk.Menu mark_menu = (Gtk.Menu)
GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMarkMenu");
mark_menu.foreach(GtkUtil.show_menuitem_accel_labels);
+ // Assemble filter menu.
+ GearyApplication.instance.load_ui_file("toolbar_filter_menu.ui");
+ Gtk.Menu filter_menu = (Gtk.Menu)
GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarFilterMenu");
+ filter_menu.foreach(GtkUtil.show_menuitem_accel_labels);
+
// Setup the application menu.
GearyApplication.instance.load_ui_file("toolbar_menu.ui");
Gtk.Menu application_menu = (Gtk.Menu)
GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMenu");
@@ -61,6 +66,11 @@ public class MainToolbar : PillHeaderbar {
insert.add(create_menu_button("folder-symbolic", move_folder_menu,
GearyController.ACTION_MOVE_MENU));
add_start(create_pill_buttons(insert));
+ // Filter.
+ insert.clear();
+ insert.add(create_menu_button("folder-saved-search-symbolic", filter_menu,
GearyController.ACTION_FILTER_MENU));
+ add_start(create_pill_buttons(insert));
+
// The toolbar looks bad when you hide one of a pair of pill buttons.
// Unfortunately, this means we have to have one pair for archive/trash
// and one single button for just trash, for when the archive button is
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 0736f80..4ad691f 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -14,6 +14,7 @@ public class MainWindow : Gtk.ApplicationWindow {
public FolderList.Tree folder_list { get; private set; default = new FolderList.Tree(); }
public ConversationListStore conversation_list_store { get; private set; default = new
ConversationListStore(); }
+ public ConversationFilter conversation_filter { get; private set; }
public MainToolbar main_toolbar { get; private set; }
public ConversationListView conversation_list_view { get; private set; }
public ConversationViewer conversation_viewer { get; private set; default = new ConversationViewer(); }
@@ -38,7 +39,9 @@ public class MainWindow : Gtk.ApplicationWindow {
title = GearyApplication.NAME;
- conversation_list_view = new ConversationListView(conversation_list_store);
+ conversation_filter = new ConversationFilter(conversation_list_store);
+
+ conversation_list_view = new ConversationListView(conversation_filter);
add_events(Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK
| Gdk.EventMask.FOCUS_CHANGE_MASK);
diff --git a/src/client/conversation-list/conversation-filter.vala
b/src/client/conversation-list/conversation-filter.vala
new file mode 100644
index 0000000..9c50f1f
--- /dev/null
+++ b/src/client/conversation-list/conversation-filter.vala
@@ -0,0 +1,100 @@
+/* Copyright 2011-2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+public class ConversationFilter : Gtk.TreeModelFilter {
+ private bool filter_unread = false;
+ private bool filter_starred = false;
+ private Gee.HashSet<Geary.App.Conversation> filtered_conversations;
+
+ public signal void conversations_added_began();
+
+ public signal void conversations_added_finished();
+
+ public ConversationFilter(ConversationListStore conversation_list_store) {
+ Object(child_model: conversation_list_store, virtual_root: null);
+
+ filtered_conversations = new Gee.HashSet<Geary.App.Conversation>();
+
+ set_visible_func(filter_func);
+
+ conversation_list_store.conversations_added_began.connect(on_conversations_added_began);
+ conversation_list_store.conversations_added_finished.connect(on_conversations_added_finished);
+ }
+
+ public void set_starred_filter(bool enabled) {
+ filter_starred = enabled;
+ filtered_conversations.clear();
+ refilter();
+ }
+
+ public void set_unread_filter(bool enabled) {
+ filter_unread = enabled;
+ filtered_conversations.clear();
+ refilter();
+ }
+
+ private bool filter_func(Gtk.TreeModel model, Gtk.TreeIter iter) {
+ Geary.App.Conversation conversation;
+ model.get(iter, ConversationListStore.Column.CONVERSATION_OBJECT, out conversation);
+
+ bool pass = ( (!filter_starred || conversation.is_flagged()) &&
+ (!filter_unread || conversation.is_unread()) );
+ if (pass) {
+ // Remember this conversation until filtering conditions change
+ filtered_conversations.add(conversation);
+ } else {
+ // Keep the conversation visible until filtering conditions change, even if user alters
+ // conversation's attributes so that the conversation would be filtered out
+ pass = filtered_conversations.contains(conversation);
+ }
+
+ return pass;
+ }
+
+ private void on_conversations_added_began() {
+ conversations_added_began();
+ }
+
+ private void on_conversations_added_finished() {
+ conversations_added_finished();
+ }
+
+ public Geary.App.Conversation? get_conversation_at_path(Gtk.TreePath path) {
+ Gtk.TreeIter iter;
+ if (!get_iter(out iter, path))
+ return null;
+
+ return get_conversation_at_iter(iter);
+ }
+
+ private Geary.App.Conversation? get_conversation_at_iter(Gtk.TreeIter iter) {
+ Geary.App.Conversation? conversation;
+ get(iter, ConversationListStore.Column.CONVERSATION_OBJECT, out conversation);
+
+ return conversation;
+ }
+
+ public Gtk.TreePath? get_path_for_conversation(Geary.App.Conversation conversation) {
+ Gtk.TreeIter iter;
+ if (!get_iter_for_conversation(conversation, out iter))
+ return null;
+
+ return get_path(iter);
+ }
+
+ private bool get_iter_for_conversation(Geary.App.Conversation conversation, out Gtk.TreeIter iter) {
+ if (!get_iter_first(out iter))
+ return false;
+
+ do {
+ if (get_conversation_at_iter(iter) == conversation)
+ return true;
+ } while (iter_next(ref iter));
+
+ return false;
+ }
+}
+
diff --git a/src/client/conversation-list/conversation-list-store.vala
b/src/client/conversation-list/conversation-list-store.vala
index 2444f7c..36a99ff 100644
--- a/src/client/conversation-list/conversation-list-store.vala
+++ b/src/client/conversation-list/conversation-list-store.vala
@@ -101,22 +101,6 @@ public class ConversationListStore : Gtk.ListStore {
email_store = (current_folder == null ? null : new Geary.App.EmailStore(current_folder.account));
}
- public Geary.App.Conversation? get_conversation_at_path(Gtk.TreePath path) {
- Gtk.TreeIter iter;
- if (!get_iter(out iter, path))
- return null;
-
- return get_conversation_at_iter(iter);
- }
-
- public Gtk.TreePath? get_path_for_conversation(Geary.App.Conversation conversation) {
- Gtk.TreeIter iter;
- if (!get_iter_for_conversation(conversation, out iter))
- return null;
-
- return get_path(iter);
- }
-
private async void refresh_previews_async(Geary.App.ConversationMonitor conversation_monitor) {
// Use a mutex because it's possible for the conversation monitor to fire multiple
// "scan-started" signals as messages come in fast and furious, but only want to process
diff --git a/src/client/conversation-list/conversation-list-view.vala
b/src/client/conversation-list/conversation-list-view.vala
index bdc1370..c72ec7e 100644
--- a/src/client/conversation-list/conversation-list-view.vala
+++ b/src/client/conversation-list/conversation-list-view.vala
@@ -14,7 +14,7 @@ public class ConversationListView : Gtk.TreeView {
private double last_upper = -1.0;
private bool reset_adjustment = false;
private Gee.Set<Geary.App.Conversation> selected = new Gee.HashSet<Geary.App.Conversation>();
- private ConversationListStore conversation_list_store;
+ private ConversationFilter conversation_filter;
private Geary.App.ConversationMonitor? conversation_monitor;
private Gee.Set<Geary.App.Conversation>? current_visible_conversations = null;
private Geary.Scheduler.Scheduled? scheduled_update_visible_conversations = null;
@@ -34,9 +34,10 @@ public class ConversationListView : Gtk.TreeView {
public signal void visible_conversations_changed(Gee.Set<Geary.App.Conversation> visible);
- public ConversationListView(ConversationListStore conversation_list_store) {
- this.conversation_list_store = conversation_list_store;
- set_model(conversation_list_store);
+ public ConversationListView(ConversationFilter conversation_filter) {
+
+ this.conversation_filter = conversation_filter;
+ set_model(conversation_filter);
set_show_expanders(false);
set_headers_visible(false);
@@ -58,8 +59,8 @@ public class ConversationListView : Gtk.TreeView {
get_model().row_deleted.connect(on_rows_changed);
get_model().row_deleted.connect(on_row_deleted);
- conversation_list_store.conversations_added_began.connect(on_conversations_added_began);
- conversation_list_store.conversations_added_finished.connect(on_conversations_added_finished);
+ conversation_filter.conversations_added_began.connect(on_conversations_added_began);
+ conversation_filter.conversations_added_finished.connect(on_conversations_added_finished);
button_press_event.connect(on_button_press);
// Set up drag and drop.
@@ -177,7 +178,7 @@ public class ConversationListView : Gtk.TreeView {
// Get the current conversation. If it's selected, we'll apply the mark operation to
// all selected conversations; otherwise, it just applies to this one.
- Geary.App.Conversation conversation = conversation_list_store.get_conversation_at_path(path);
+ Geary.App.Conversation conversation = conversation_filter.get_conversation_at_path(path);
Gee.Collection<Geary.App.Conversation> to_mark;
if (GearyApplication.instance.controller.get_selected_conversations().contains(conversation))
to_mark = GearyApplication.instance.controller.get_selected_conversations();
@@ -214,7 +215,7 @@ public class ConversationListView : Gtk.TreeView {
return true;
if (event.button == 3 && event.type == Gdk.EventType.BUTTON_PRESS) {
- Geary.App.Conversation conversation = conversation_list_store.get_conversation_at_path(path);
+ Geary.App.Conversation conversation = conversation_filter.get_conversation_at_path(path);
string?[] action_names = {};
action_names += GearyController.ACTION_DELETE_MESSAGE;
@@ -328,7 +329,7 @@ public class ConversationListView : Gtk.TreeView {
// Conversations are selected, so collect them and signal if different
Gee.HashSet<Geary.App.Conversation> new_selected = new Gee.HashSet<Geary.App.Conversation>();
foreach (Gtk.TreePath path in paths) {
- Geary.App.Conversation? conversation = conversation_list_store.get_conversation_at_path(path);
+ Geary.App.Conversation? conversation = conversation_filter.get_conversation_at_path(path);
if (conversation != null)
new_selected.add(conversation);
}
@@ -349,7 +350,7 @@ public class ConversationListView : Gtk.TreeView {
return visible_conversations;
while (start_path.compare(end_path) <= 0) {
- Geary.App.Conversation? conversation =
conversation_list_store.get_conversation_at_path(start_path);
+ Geary.App.Conversation? conversation = conversation_filter.get_conversation_at_path(start_path);
if (conversation != null)
visible_conversations.add(conversation);
@@ -363,7 +364,7 @@ public class ConversationListView : Gtk.TreeView {
Gee.HashSet<Geary.App.Conversation> selected_conversations = new
Gee.HashSet<Geary.App.Conversation>();
foreach (Gtk.TreePath path in get_all_selected_paths()) {
- Geary.App.Conversation? conversation = conversation_list_store.get_conversation_at_path(path);
+ Geary.App.Conversation? conversation = conversation_filter.get_conversation_at_path(path);
if (path != null)
selected_conversations.add(conversation);
}
@@ -400,7 +401,7 @@ public class ConversationListView : Gtk.TreeView {
}
public void select_conversation(Geary.App.Conversation conversation) {
- Gtk.TreePath path = conversation_list_store.get_path_for_conversation(conversation);
+ Gtk.TreePath path = conversation_filter.get_path_for_conversation(conversation);
if (path != null)
set_cursor(path, null, false);
}
@@ -408,7 +409,7 @@ public class ConversationListView : Gtk.TreeView {
public void select_conversations(Gee.Set<Geary.App.Conversation> conversations) {
Gtk.TreeSelection selection = get_selection();
foreach (Geary.App.Conversation conversation in conversations) {
- Gtk.TreePath path = conversation_list_store.get_path_for_conversation(conversation);
+ Gtk.TreePath path = conversation_filter.get_path_for_conversation(conversation);
if (path != null)
selection.select_path(path);
}
@@ -438,7 +439,7 @@ public class ConversationListView : Gtk.TreeView {
}
private void on_row_activated(Gtk.TreePath path) {
- Geary.App.Conversation? c = conversation_list_store.get_conversation_at_path(path);
+ Geary.App.Conversation? c = conversation_filter.get_conversation_at_path(path);
if (c != null)
conversation_activated(c);
}
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index cdf0f7b..fc39051 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -15,5 +15,6 @@ install(FILES password-dialog.glade DESTINATION ${UI_DEST})
install(FILES preferences.glade DESTINATION ${UI_DEST})
install(FILES remove_confirm.glade DESTINATION ${UI_DEST})
install(FILES toolbar_mark_menu.ui DESTINATION ${UI_DEST})
+install(FILES toolbar_filter_menu.ui DESTINATION ${UI_DEST})
install(FILES toolbar_menu.ui DESTINATION ${UI_DEST})
install(FILES upgrade_dialog.glade DESTINATION ${UI_DEST})
diff --git a/ui/toolbar_filter_menu.ui b/ui/toolbar_filter_menu.ui
new file mode 100644
index 0000000..e7f50c6
--- /dev/null
+++ b/ui/toolbar_filter_menu.ui
@@ -0,0 +1,9 @@
+<ui>
+ <popup name="ToolbarFilterMenu">
+ <menuitem name="ShowAll" action="GearyFilterShowAll" />
+ <separator />
+ <menuitem name="ShowUnread" action="GearyFilterShowUnread" />
+ <menuitem name="ShowStarred" action="GearyFilterShowStarred" />
+ </popup>
+</ui>
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]