[geary/wip/713190-resort-2] Clean up of ConversationListStore, improved lookup performance
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/713190-resort-2] Clean up of ConversationListStore, improved lookup performance
- Date: Thu, 22 Jan 2015 00:09:31 +0000 (UTC)
commit 1e5dba3565a9427faca63270132ad5118d46d8e2
Author: Jim Nelson <jim yorba org>
Date: Wed Jan 21 16:09:14 2015 -0800
Clean up of ConversationListStore, improved lookup performance
src/client/application/geary-controller.vala | 5 -
.../conversation-list/conversation-list-store.vala | 109 ++++++++++++++------
2 files changed, 75 insertions(+), 39 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index d451af3..0892e13 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -1117,8 +1117,6 @@ public class GearyController : Geary.BaseObject {
account.sending_monitor.start.disconnect(on_sending_started);
account.sending_monitor.finish.disconnect(on_sending_finished);
- if (main_window.conversation_list_store.account_owner_email == account.information.email)
- main_window.conversation_list_store.account_owner_email = null;
main_window.folder_list.remove_account(account);
if (inboxes.has_key(account)) {
@@ -1310,9 +1308,6 @@ public class GearyController : Geary.BaseObject {
if (!(current_folder is Geary.SearchFolder))
previous_non_search_folder = current_folder;
- main_window.conversation_list_store.set_current_folder(current_folder, conversation_cancellable);
- main_window.conversation_list_store.account_owner_email = current_account.information.email;
-
main_window.main_toolbar.copy_folder_menu.clear();
main_window.main_toolbar.move_folder_menu.clear();
foreach(Geary.Folder f in current_folder.account.list_folders()) {
diff --git a/src/client/conversation-list/conversation-list-store.vala
b/src/client/conversation-list/conversation-list-store.vala
index b35c0dd..31b5050 100644
--- a/src/client/conversation-list/conversation-list-store.vala
+++ b/src/client/conversation-list/conversation-list-store.vala
@@ -22,12 +22,14 @@ public class ConversationListStore : Gtk.ListStore {
public enum Column {
CONVERSATION_DATA,
- CONVERSATION_OBJECT;
+ CONVERSATION_OBJECT,
+ ROW_WRAPPER;
public static Type[] get_types() {
return {
typeof (FormattedConversationData), // CONVERSATION_DATA
- typeof (Geary.App.Conversation) // CONVERSATION_OBJECT
+ typeof (Geary.App.Conversation), // CONVERSATION_OBJECT
+ typeof (RowWrapper) // ROW_WRAPPER
};
}
@@ -35,23 +37,49 @@ public class ConversationListStore : Gtk.ListStore {
switch (this) {
case CONVERSATION_DATA:
return "data";
+
case CONVERSATION_OBJECT:
return "envelope";
+ case ROW_WRAPPER:
+ return "wrapper";
+
default:
assert_not_reached();
}
}
}
- public string? account_owner_email { get; set; default = null; }
+ private class RowWrapper : Geary.BaseObject {
+ public Geary.App.Conversation conversation;
+ public Gtk.TreeRowReference row;
+
+ public RowWrapper(Gtk.TreeModel model, Geary.App.Conversation conversation, Gtk.TreePath path) {
+ this.conversation = conversation;
+ this.row = new Gtk.TreeRowReference(model, path);
+ }
+
+ public Gtk.TreePath get_path() {
+ return row.get_path();
+ }
+
+ public Gtk.TreeIter get_iter() {
+ Gtk.TreeIter iter;
+ bool valid = row.get_model().get_iter(out iter, get_path());
+ assert(valid);
+
+ return iter;
+ }
+ }
+
public Geary.ProgressMonitor preview_monitor { get; private set; default =
new Geary.SimpleProgressMonitor(Geary.ProgressType.ACTIVITY); }
private Geary.App.ConversationMonitor conversation_monitor;
- private Geary.Folder? current_folder = null;
+ private Gee.HashMap<Geary.App.Conversation, RowWrapper> row_map = new Gee.HashMap<
+ Geary.App.Conversation, RowWrapper>();
private Geary.App.EmailStore? email_store = null;
- private Cancellable? cancellable_folder = null;
+ private Cancellable cancellable = new Cancellable();
private bool loading_local_only = true;
private Geary.Nonblocking.Mutex refresh_mutex = new Geary.Nonblocking.Mutex();
private uint update_id = 0;
@@ -76,6 +104,9 @@ public class ConversationListStore : Gtk.ListStore {
~ConversationListStore() {
if (update_id != 0)
Source.remove(update_id);
+
+ GearyApplication.instance.controller.notify[GearyController.PROP_CURRENT_CONVERSATION].
+ disconnect(on_conversation_monitor_changed);
}
private void on_conversation_monitor_changed() {
@@ -88,10 +119,17 @@ public class ConversationListStore : Gtk.ListStore {
conversation_monitor.email_flags_changed.disconnect(on_email_flags_changed);
}
+ cancellable.cancel();
+ cancellable = new Cancellable();
+
clear();
+ row_map.clear();
conversation_monitor = GearyApplication.instance.controller.current_conversations;
+ email_store = null;
if (conversation_monitor != null) {
+ email_store = new Geary.App.EmailStore(conversation_monitor.folder.account);
+
// add all existing conversations
on_conversations_added(conversation_monitor.get_conversations());
@@ -104,12 +142,6 @@ public class ConversationListStore : Gtk.ListStore {
}
}
- public void set_current_folder(Geary.Folder? current_folder, Cancellable? cancellable_folder) {
- this.current_folder = current_folder;
- this.cancellable_folder = cancellable_folder;
- 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))
@@ -118,14 +150,6 @@ public class ConversationListStore : Gtk.ListStore {
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
@@ -155,7 +179,7 @@ public class ConversationListStore : Gtk.ListStore {
// should only be called by refresh_previews_async()
private async void do_refresh_previews_async(Geary.App.ConversationMonitor conversation_monitor) {
- if (current_folder == null || !GearyApplication.instance.config.display_preview)
+ if (conversation_monitor == null || !GearyApplication.instance.config.display_preview)
return;
Gee.Set<Geary.EmailIdentifier> needing_previews = get_emails_needing_previews();
@@ -166,7 +190,7 @@ public class ConversationListStore : Gtk.ListStore {
if (emails.size < 1)
return;
- debug("Displaying %d previews for %s...", emails.size, current_folder.to_string());
+ debug("Displaying %d previews for %s...", emails.size, conversation_monitor.folder.to_string());
foreach (Geary.Email email in emails) {
Geary.App.Conversation? conversation = conversation_monitor.get_conversation_for_email(email.id);
if (conversation != null)
@@ -174,7 +198,7 @@ public class ConversationListStore : Gtk.ListStore {
else
debug("Couldn't find conversation for %s", email.id.to_string());
}
- debug("Displayed %d previews for %s", emails.size, current_folder.to_string());
+ debug("Displayed %d previews for %s", emails.size, conversation_monitor.folder.to_string());
}
private async Gee.Collection<Geary.Email> do_get_previews_async(
@@ -185,7 +209,7 @@ public class ConversationListStore : Gtk.ListStore {
try {
debug("Loading %d previews...", emails_needing_previews.size);
emails = yield email_store.list_email_by_sparse_id_async(emails_needing_previews,
- ConversationListStore.WITH_PREVIEW_FIELDS, flags, cancellable_folder);
+ ConversationListStore.WITH_PREVIEW_FIELDS, flags, cancellable);
debug("Loaded %d previews...", emails_needing_previews.size);
} catch (Error err) {
// Ignore NOT_FOUND, as that's entirely possible when waiting for the remote to open
@@ -260,10 +284,19 @@ public class ConversationListStore : Gtk.ListStore {
private void set_row(Gtk.TreeIter iter, Geary.App.Conversation conversation, Geary.Email preview) {
FormattedConversationData conversation_data = new FormattedConversationData(conversation,
- preview, current_folder, account_owner_email);
+ preview, conversation_monitor.folder, conversation_monitor.folder.account.information.email);
+
+ Gtk.TreePath? path = get_path(iter);
+ assert(path != null);
+ RowWrapper wrapper = new RowWrapper(this, conversation, path);
+
set(iter,
Column.CONVERSATION_DATA, conversation_data,
- Column.CONVERSATION_OBJECT, conversation);
+ Column.CONVERSATION_OBJECT, conversation,
+ Column.ROW_WRAPPER, wrapper
+ );
+
+ row_map.set(conversation, wrapper);
}
private void refresh_conversation(Geary.App.Conversation conversation) {
@@ -318,20 +351,26 @@ public class ConversationListStore : Gtk.ListStore {
row_changed(path, iter);
}
- private bool get_iter_for_conversation(Geary.App.Conversation conversation, out Gtk.TreeIter iter) {
- if (!get_iter_first(out iter))
- return false;
+ public Gtk.TreePath? get_path_for_conversation(Geary.App.Conversation conversation) {
+ RowWrapper? wrapper = row_map.get(conversation);
- do {
- if (get_conversation_at_iter(iter) == conversation)
- return true;
- } while (iter_next(ref iter));
+ return (wrapper != null) ? wrapper.get_path() : null;
+ }
+
+ private bool get_iter_for_conversation(Geary.App.Conversation conversation, out Gtk.TreeIter iter) {
+ // use get_iter_first() because boxing Gtk.TreeIter with a nullable is problematic with
+ // current bindings
+ RowWrapper? wrapper = row_map.get(conversation);
+ if (wrapper != null)
+ iter = wrapper.get_iter();
+ else
+ get_iter_first(out iter);
- return false;
+ return wrapper != null;
}
private bool has_conversation(Geary.App.Conversation conversation) {
- return get_iter_for_conversation(conversation, null);
+ return row_map.has_key(conversation);
}
private Geary.App.Conversation? get_conversation_at_iter(Gtk.TreeIter iter) {
@@ -352,6 +391,8 @@ public class ConversationListStore : Gtk.ListStore {
Gtk.TreeIter iter;
if (get_iter_for_conversation(conversation, out iter))
remove(iter);
+
+ row_map.remove(conversation);
}
private bool add_conversation(Geary.App.Conversation conversation) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]