[geary] Fix messages being selected after move/etc and autoselect is disabled.



commit 310daa8ad03878fd70353d9806b7dd66fd7cce33
Author: Michael James Gratton <mike vee net>
Date:   Thu Oct 20 16:27:43 2016 +1100

    Fix messages being selected after move/etc and autoselect is disabled.
    
    Bug 773054
    
    * src/client/conversation-list/conversation-list-view.vala: Disable all
      selection when the user is causing the selection will change. This
      prevents the GtkTreeView impl from selecting the next row after rows
      are removed as a result of user action, but not for some other reason,
      i.e. the server removing a message.
    
    * src/client/application/geary-controller.vala: Call new
      ConversationListView::set_changing_selection as needed when moving
      messages.
    
    * src/client/conversation-list/conversation-list-store,
      src/engine/app/app-conversation-monitor.vala: Rename
      conversation_removed signal to conversations_removed and change its
      param to be a collection of conversations, so we can re-enable
      ConversationListView selection only after all conversations have been
      removed. Update call sites.

 src/client/application/geary-controller.vala       |   25 +++++++++---
 .../conversation-list/conversation-list-store.vala |   13 ++++--
 .../conversation-list/conversation-list-view.vala  |   40 ++++++++++++++++----
 src/engine/app/app-conversation-monitor.vala       |   21 +++++-----
 4 files changed, 68 insertions(+), 31 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 15cb7eb..a7a6468 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -1442,7 +1442,7 @@ public class GearyController : Geary.BaseObject {
         current_conversations.seed_completed.connect(on_conversation_count_changed);
         current_conversations.scan_completed.connect(on_conversation_count_changed);
         current_conversations.conversations_added.connect(on_conversation_count_changed);
-        current_conversations.conversation_removed.connect(on_conversation_count_changed);
+        current_conversations.conversations_removed.connect(on_conversation_count_changed);
         
         if (!current_conversations.is_monitoring)
             yield current_conversations.start_monitoring_async(conversation_cancellable);
@@ -1960,12 +1960,19 @@ public class GearyController : Geary.BaseObject {
         Gee.List<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
         if (ids.size == 0)
             return;
-        
+
+        this.main_window.conversation_list_view.set_changing_selection(true);
+
         Geary.FolderSupport.Move? supports_move = current_folder as Geary.FolderSupport.Move;
         if (supports_move != null)
-            move_conversation_async.begin(supports_move, ids, destination.path, cancellable_folder);
+            move_conversation_async.begin(
+                supports_move, ids, destination.path, cancellable_folder,
+                (obj, ret) => {
+                    move_conversation_async.end(ret);
+                    this.main_window.conversation_list_view.set_changing_selection(false);
+                });
     }
-    
+
     private async void move_conversation_async(Geary.FolderSupport.Move source_folder,
         Gee.List<Geary.EmailIdentifier> ids, Geary.FolderPath destination, Cancellable? cancellable) {
         try {
@@ -2572,9 +2579,12 @@ public class GearyController : Geary.BaseObject {
         last_deleted_conversation = selected_conversations.size > 0
             ? Geary.traverse<Geary.App.Conversation>(selected_conversations).first() : null;
         
-        // Return focus to the conversation list from the clicked toolbar button.
-        main_window.conversation_list_view.grab_focus();
-        
+        // Return focus to the conversation list from the clicked
+        // toolbar button.
+        this.main_window.conversation_list_view.grab_focus();
+
+        this.main_window.conversation_list_view.set_changing_selection(true);
+
         Gee.List<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
         if (archive) {
             debug("Archiving selected messages");
@@ -2629,6 +2639,7 @@ public class GearyController : Geary.BaseObject {
         } catch (Error e) {
             debug("Unable to archive/trash/delete messages: %s", e.message);
         }
+        this.main_window.conversation_list_view.set_changing_selection(false);
     }
     
     private void save_revokable(Geary.Revokable? new_revokable, string? description) {
diff --git a/src/client/conversation-list/conversation-list-store.vala 
b/src/client/conversation-list/conversation-list-store.vala
index 6a8fd2a..7c3bc69 100644
--- a/src/client/conversation-list/conversation-list-store.vala
+++ b/src/client/conversation-list/conversation-list-store.vala
@@ -92,8 +92,8 @@ public class ConversationListStore : Gtk.ListStore {
     private uint update_id = 0;
     
     public signal void conversations_added_began();
-    
     public signal void conversations_added_finished();
+    public signal void conversations_removed(bool start);
 
     public ConversationListStore(Geary.App.ConversationMonitor conversations) {
         set_column_types(Column.get_types());
@@ -112,7 +112,7 @@ public class ConversationListStore : Gtk.ListStore {
 
         conversations.scan_completed.connect(on_scan_completed);
         conversations.conversations_added.connect(on_conversations_added);
-        conversations.conversation_removed.connect(on_conversation_removed);
+        conversations.conversations_removed.connect(on_conversations_removed);
         conversations.conversation_appended.connect(on_conversation_appended);
         conversations.conversation_trimmed.connect(on_conversation_trimmed);
         conversations.email_flags_changed.connect(on_email_flags_changed);
@@ -428,10 +428,13 @@ public class ConversationListStore : Gtk.ListStore {
         conversations_added_finished();
     }
     
-    private void on_conversation_removed(Geary.App.Conversation conversation) {
-        remove_conversation(conversation);
+    private void on_conversations_removed(Gee.Collection<Geary.App.Conversation> conversations) {
+        conversations_removed(true);
+        foreach (Geary.App.Conversation removed in conversations)
+            remove_conversation(removed);
+        conversations_removed(false);
     }
-    
+
     private void on_conversation_appended(Geary.App.Conversation conversation) {
         if (has_conversation(conversation)) {
             refresh_conversation(conversation);
diff --git a/src/client/conversation-list/conversation-list-view.vala 
b/src/client/conversation-list/conversation-list-view.vala
index 355681e..20366ea 100644
--- a/src/client/conversation-list/conversation-list-view.vala
+++ b/src/client/conversation-list/conversation-list-view.vala
@@ -19,6 +19,7 @@ public class ConversationListView : Gtk.TreeView {
     private Gtk.Menu? context_menu = null;
     private Gee.Set<Geary.App.Conversation> selected = new Gee.HashSet<Geary.App.Conversation>();
     private uint selection_changed_id = 0;
+    private bool suppress_selection = false;
 
     public signal void conversations_selected(Gee.Set<Geary.App.Conversation> selected);
     
@@ -83,6 +84,7 @@ public class ConversationListView : Gtk.TreeView {
             old_store.conversations_added_began.disconnect(
                 on_conversations_added_began
             );
+            old_store.conversations_removed.disconnect(on_conversations_removed);
             old_store.row_inserted.disconnect(on_rows_changed);
             old_store.rows_reordered.disconnect(on_rows_changed);
             old_store.row_changed.disconnect(on_rows_changed);
@@ -102,6 +104,7 @@ public class ConversationListView : Gtk.TreeView {
             new_store.conversations_added_finished.connect(
                 on_conversations_added_finished
             );
+            new_store.conversations_removed.connect(on_conversations_removed);
         }
 
         // Disconnect the selection handler since we don't want to
@@ -113,12 +116,27 @@ public class ConversationListView : Gtk.TreeView {
         selection.changed.connect(on_selection_changed);
     }
 
+    /**
+     * Specifies an action is currently changing the view's selection.
+     */
+    public void set_changing_selection(bool is_changing) {
+        // Make sure that when not autoselecting, and if the user is
+        // causing selected rows to be removed, the next row is not
+        // automatically selected by GtkTreeView
+        if (is_changing) {
+            this.suppress_selection =
+                !GearyApplication.instance.config.autoselect;
+        } else {
+            // If no longer changing, always re-enable selection
+            get_selection().set_mode(Gtk.SelectionMode.MULTIPLE);
+        }
+    }
+
     private void on_conversation_monitor_changed() {
         if (conversation_monitor != null) {
             conversation_monitor.scan_started.disconnect(on_scan_started);
             conversation_monitor.scan_completed.disconnect(on_scan_completed);
             conversation_monitor.seed_completed.disconnect(on_seed_completed);
-            conversation_monitor.conversation_removed.disconnect(on_conversation_removed);
         }
         
         conversation_monitor = GearyApplication.instance.controller.current_conversations;
@@ -127,7 +145,6 @@ public class ConversationListView : Gtk.TreeView {
             conversation_monitor.scan_started.connect(on_scan_started);
             conversation_monitor.scan_completed.connect(on_scan_completed);
             conversation_monitor.seed_completed.connect(on_seed_completed);
-            conversation_monitor.conversation_removed.connect(on_conversation_removed);
         }
     }
     
@@ -157,11 +174,6 @@ public class ConversationListView : Gtk.TreeView {
         }
     }
 
-    private void on_conversation_removed(Geary.App.Conversation conversation) {
-        if (!GearyApplication.instance.config.autoselect)
-            get_selection().unselect_all();
-    }
-    
     private void on_conversations_added_began() {
         Gtk.Adjustment? adjustment = get_adjustment();
         // If we were at the top, we want to stay there after conversations are added.
@@ -184,7 +196,19 @@ public class ConversationListView : Gtk.TreeView {
         
         adjustment.set_value(0);
     }
-    
+
+    private void on_conversations_removed(bool start) {
+        if (!GearyApplication.instance.config.autoselect) {
+            Gtk.SelectionMode mode = start
+                // Stop GtkTreeView from automatically selecting the
+                // next row after the removed rows
+                ? Gtk.SelectionMode.NONE
+                // Allow the user to make selections again
+                : Gtk.SelectionMode.MULTIPLE;
+            get_selection().set_mode(mode);
+        }
+    }
+
     private Gtk.Adjustment? get_adjustment() {
         Gtk.ScrolledWindow? parent = get_parent() as Gtk.ScrolledWindow;
         if (parent == null) {
diff --git a/src/engine/app/app-conversation-monitor.vala b/src/engine/app/app-conversation-monitor.vala
index b906155..c974a99 100644
--- a/src/engine/app/app-conversation-monitor.vala
+++ b/src/engine/app/app-conversation-monitor.vala
@@ -112,15 +112,15 @@ public class Geary.App.ConversationMonitor : BaseObject {
     /**
      * "conversations-removed" is fired when all the email in a Conversation has been removed.
      * It's possible this will be called without a signal alerting that it's emails have been
-     * removed, i.e. a "conversation-removed" signal may fire with no accompanying
+     * removed, i.e. a "conversations-removed" signal may fire with no accompanying
      * "conversation-trimmed".
      *
      * Note that this can only occur when monitoring is enabled.  There is (currently) no
      * user call to manually remove email from Conversations.
      */
-    public virtual signal void conversation_removed(Conversation conversation) {
-        Logging.debug(Logging.Flag.CONVERSATIONS, "[%s] ConversationMonitor::conversation_removed",
-            folder.to_string());
+    public virtual signal void conversations_removed(Gee.Collection<Conversation> conversations) {
+        Logging.debug(Logging.Flag.CONVERSATIONS, "[%s] ConversationMonitor::conversations_removed %d",
+            folder.to_string(), conversations.size);
     }
     
     /**
@@ -216,8 +216,8 @@ public class Geary.App.ConversationMonitor : BaseObject {
         conversations_added(conversations);
     }
     
-    protected virtual void notify_conversation_removed(Conversation conversation) {
-        conversation_removed(conversation);
+    protected virtual void notify_conversations_removed(Gee.Collection<Conversation> conversations) {
+        conversations_removed(conversations);
     }
     
     protected virtual void notify_conversation_appended(Conversation conversation,
@@ -583,9 +583,8 @@ public class Geary.App.ConversationMonitor : BaseObject {
             // fall-through
         }
         
-        if (removed_due_to_merge != null) {
-            foreach (Conversation conversation in removed_due_to_merge)
-                notify_conversation_removed(conversation);
+        if (removed_due_to_merge != null && removed_due_to_merge.size > 0) {
+            notify_conversations_removed(removed_due_to_merge);
         }
         
         if (added != null && added.size > 0)
@@ -637,8 +636,8 @@ public class Geary.App.ConversationMonitor : BaseObject {
         foreach (Conversation conversation in trimmed.get_keys())
             notify_conversation_trimmed(conversation, trimmed.get(conversation));
         
-        foreach (Conversation conversation in removed)
-            notify_conversation_removed(conversation);
+        if (removed.size > 0)
+            notify_conversations_removed(removed);
         
         // For any still-existing conversations that we've trimmed messages
         // from, do a search for any messages that should still be there due to


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]