Prevent MessageListView's "conversations-selected" firing multiple times

This is to assist in completing ticket #5128, where because this
signal is fired multiple times although no state has changed (due
to Gtk.TreeSelection's "changed" signal wierdness) it's causing
the entire UI to update state unnecessarily.

This ticket may also assist in fixing #5327, but it does not close
that bug.
This commit is contained in:
Jim Nelson 2012-07-02 14:53:08 -07:00
parent 65e3550e90
commit c734c54b00
3 changed files with 56 additions and 25 deletions

View file

@ -76,7 +76,7 @@ public class GearyController {
private Geary.ConversationMonitor? current_conversations = null;
private bool loading_local_only = true;
private int busy_count = 0;
private Geary.Conversation[] selected_conversations = new Geary.Conversation[0];
private Gee.Set<Geary.Conversation> selected_conversations = new Gee.HashSet<Geary.Conversation>();
private Geary.Conversation? last_deleted_conversation = null;
private bool scan_in_progress = false;
private int conversations_added_counter = 0;
@ -311,8 +311,8 @@ public class GearyController {
}
private bool is_viewed_conversation(Geary.Conversation? conversation) {
return conversation != null && selected_conversations.length > 0 &&
selected_conversations[0] == conversation;
return conversation != null && selected_conversations.size > 0 &&
Geary.Collection.get_first<Geary.Conversation>(selected_conversations) == conversation;
}
// Update widgets and such to match capabilities of the current folder ... sensitivity is handled
@ -626,20 +626,23 @@ public class GearyController {
set_busy(false);
}
private void on_conversations_selected(Geary.Conversation[] conversations) {
private void on_conversations_selected(Gee.Set<Geary.Conversation> selected) {
debug("on_conversations_selected: %d", selected.size);
cancel_message();
selected_conversations = conversations;
selected_conversations = selected;
// Disable message buttons until conversation loads.
enable_message_buttons(false);
if (conversations.length == 1 && current_folder != null) {
do_show_message.begin(conversations[0].get_email(Geary.Conversation.Ordering.DATE_ASCENDING),
if (selected.size == 1 && current_folder != null) {
Geary.Conversation conversation = Geary.Collection.get_first(selected);
do_show_message.begin(conversation.get_email(Geary.Conversation.Ordering.DATE_ASCENDING),
cancellable_message, on_show_message_completed);
} else if (current_folder != null) {
main_window.message_viewer.show_multiple_selected(conversations.length);
if (conversations.length > 1) {
main_window.message_viewer.show_multiple_selected(selected.size);
if (selected.size > 1) {
enable_multiple_message_buttons();
} else {
enable_message_buttons(false);
@ -975,7 +978,7 @@ public class GearyController {
private void on_copy_conversation(Geary.Folder destination) {
// Nothing to do if nothing selected.
if (selected_conversations == null || selected_conversations.length == 0)
if (selected_conversations == null || selected_conversations.size == 0)
return;
Gee.List<Geary.EmailIdentifier> ids = get_selected_ids();
@ -997,7 +1000,7 @@ public class GearyController {
private void on_move_conversation(Geary.Folder destination) {
// Nothing to do if nothing selected.
if (selected_conversations == null || selected_conversations.length == 0)
if (selected_conversations == null || selected_conversations.size == 0)
return;
Gee.List<Geary.EmailIdentifier> ids = get_selected_ids();
@ -1155,7 +1158,8 @@ public class GearyController {
// There should always be at least one conversation selected here, otherwise the archive
// button is disabled, but better safe than segfaulted.
last_deleted_conversation = selected_conversations.length > 0 ? selected_conversations[0] : null;
last_deleted_conversation = selected_conversations.size > 0
? Geary.Collection.get_first<Geary.Conversation>(selected_conversations) : null;
// If the user clicked the toolbar button, we want to move focus back to the message list.
main_window.message_list_view.grab_focus();

View file

@ -12,9 +12,12 @@ public class MessageListView : Gtk.TreeView {
// Used to avoid repeated calls to load_more(). Contains the last "upper" bound of the
// scroll adjustment seen at the call to load_more().
private double last_upper = -1.0;
private Gee.Set<Geary.Conversation> selected = new Gee.HashSet<Geary.Conversation>();
public signal void conversations_selected(Gee.Set<Geary.Conversation> selected);
public signal void conversations_selected(Geary.Conversation[] conversations);
public signal void load_more();
public signal void mark_conversation(Geary.Conversation conversation,
Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove, bool only_mark_preview);
@ -122,25 +125,35 @@ public class MessageListView : Gtk.TreeView {
private Gtk.TreePath? get_selected_path() {
return get_all_selected_paths().nth_data(0);
}
// Gtk.TreeSelection can fire its "changed" signal even when nothing's changed, so look for that
// and prevent to avoid subscribers from doing the same things multiple times
private void on_selection_changed() {
// Get the selected paths. If no paths are selected then notify of that immediately.
debug("on_selection_changed");
List<Gtk.TreePath> paths = get_all_selected_paths();
Geary.Conversation[] conversations = new Geary.Conversation[0];
if (paths.length() == 0) {
conversations_selected(conversations);
// only notify if this is different than what was previously reported
if (selected.size != 0) {
selected.clear();
conversations_selected(selected.read_only_view);
}
return;
}
// Conversations are selected, so lets collect all of their conversations and signal.
// Conversations are selected, so collect them and signal if different
Gee.HashSet<Geary.Conversation> new_selected = new Gee.HashSet<Geary.Conversation>();
foreach (Gtk.TreePath path in paths) {
Geary.Conversation? conversation = get_store().get_conversation_at(path);
if (conversation != null) {
conversations += conversation;
}
if (conversation != null)
new_selected.add(conversation);
}
if (conversations.length != 0) {
conversations_selected(conversations);
// only notify if different than what was previously reported
if (!Geary.Collection.are_sets_equal<Geary.Conversation>(selected, new_selected)) {
selected = new_selected;
conversations_selected(selected.read_only_view);
}
}

View file

@ -14,7 +14,21 @@ public Gee.ArrayList<G> to_array_list<G>(Gee.Collection<G> c) {
}
public G? get_first<G>(Gee.Collection<G> c) {
return c.iterator().get();
Gee.Iterator<G> iter = c.iterator();
return iter.next() ? iter.get() : null;
}
public bool are_sets_equal<G>(Gee.Set<G> a, Gee.Set<G> b) {
if (a.size != b.size)
return false;
foreach (G element in a) {
if (!b.contains(element))
return false;
}
return true;
}
}