[geary/wip/765516-gtk-widget-conversation-viewer: 81/119] Add support for easier iterating over conversation email and msg views.



commit 2893b9ee0d4dc3eb87d4439d1b23deb09d309cc5
Author: Michael James Gratton <mike vee net>
Date:   Sun Jul 10 21:56:14 2016 +1000

    Add support for easier iterating over conversation email and msg views.

 .../conversation-viewer/conversation-email.vala    |   73 ++++++++++++++++++++
 .../conversation-viewer/conversation-viewer.vala   |   62 ++++++++++-------
 2 files changed, 110 insertions(+), 25 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-email.vala 
b/src/client/conversation-viewer/conversation-email.vala
index 5e7e742..d03e394 100644
--- a/src/client/conversation-viewer/conversation-email.vala
+++ b/src/client/conversation-viewer/conversation-email.vala
@@ -18,6 +18,72 @@
 [GtkTemplate (ui = "/org/gnome/Geary/conversation-email.ui")]
 public class ConversationEmail : Gtk.Box {
 
+    /**
+     * Iterator that returns all message views in an email view.
+     */
+    private class MessageViewIterator :
+        Gee.Traversable<ConversationMessage>, Gee.Iterator<ConversationMessage>, Object {
+
+        public bool read_only {
+            get { return true; }
+        }
+        public bool valid {
+            get { return this.pos == 0 || this.attached_views.valid; }
+        }
+
+        private ConversationEmail parent_view;
+        private int pos = -1;
+        private Gee.Iterator<ConversationMessage>? attached_views = null;
+
+        internal MessageViewIterator(ConversationEmail parent_view) {
+            this.parent_view = parent_view;
+            this.attached_views = parent_view._attached_messages.iterator();
+        }
+
+        public bool next() {
+            if (!has_next()) {
+                return false;
+            }
+            if (this.pos == -1) {
+                this.pos = 0;
+            } else {
+                this.attached_views.next();
+            }
+            return true;
+        }
+
+        public bool has_next() {
+            return this.pos == -1 || this.attached_views.next();
+        }
+
+        public new ConversationMessage get() {
+            switch (this.pos) {
+            case -1:
+                assert_not_reached();
+
+            case 0:
+                this.pos = 1;
+                return this.parent_view.primary_message;
+
+            default:
+                return this.attached_views.get();
+            }
+        }
+
+        public void remove() {
+            assert_not_reached();
+        }
+
+        public new bool foreach(Gee.ForallFunc<ConversationMessage> f) {
+            this.pos = 1;
+            bool ret = f(this.parent_view.primary_message);
+            if (ret) {
+                ret = this.attached_views.foreach(f);
+            }
+            return ret;
+        }
+
+    }
 
     /**
      * Information related to a specific attachment.
@@ -392,6 +458,13 @@ public class ConversationEmail : Gtk.Box {
         remove(embed);
     }
 
+    /**
+     * Returns a new Iterable over all message views in this email view
+     */
+    internal Gee.Iterator<ConversationMessage> message_view_iterator() {
+        return new MessageViewIterator(this);
+    }
+
     private SimpleAction add_action(string name) {
         SimpleAction action = new SimpleAction(name, null);
         message_actions.add_action(action);
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index 74acfa7..b6e7df8 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -320,6 +320,26 @@ public class ConversationViewer : Gtk.Stack {
     }
 
     /**
+     * Returns an new Iterable over all email views in the viewer
+     */
+    private Gee.Iterator<ConversationEmail> email_view_iterator() {
+        return this.email_to_row.values.map<ConversationEmail>((row) => {
+                return (ConversationEmail) row.get_child();
+            });
+    }
+
+    /**
+     * Returns a new Iterable over all message views in the viewer
+     */
+    private Gee.Iterator<ConversationMessage> message_view_iterator() {
+        return Gee.Iterator.concat<ConversationMessage>(
+            email_view_iterator().map<Gee.Iterator<ConversationMessage>>(
+                (email_view) => { return email_view.message_view_iterator(); }
+            )
+        );
+    }
+
+    /**
      * Finds any currently visible messages, marks them as being read.
      */
     private void check_mark_read() {
@@ -330,17 +350,15 @@ public class ConversationViewer : Gtk.Stack {
         int top_bound = (int) adj.value;
         int bottom_bound = top_bound + (int) adj.page_size;
 
-        const int TEXT_PADDING = 50;
-        foreach (Geary.Email email in emails) {
-            ConversationEmail conversation_email = conversation_email_for_id(email.id);
-            ConversationMessage conversation_message =
-                conversation_email.primary_message;
+        email_view_iterator().foreach((email_view) => {
+            const int TEXT_PADDING = 50;
+            ConversationMessage conversation_message = email_view.primary_message;
             // Don't bother with not-yet-loaded emails since the
             // size of the body will be off, affecting the visibility
             // of emails further down the conversation.
-            if (email.email_flags.is_unread() &&
+            if (email_view.email.email_flags.is_unread() &&
                 conversation_message.is_loading_complete &&
-                !conversation_email.is_manual_read()) {
+                !email_view.is_manual_read()) {
                  int body_top = 0;
                  int body_left = 0;
                  conversation_message.web_view.translate_coordinates(
@@ -354,15 +372,16 @@ public class ConversationViewer : Gtk.Stack {
                  // Only mark the email as read if it's actually visible
                  if (body_bottom > top_bound &&
                      body_top + TEXT_PADDING < bottom_bound) {
-                     email_ids.add(email.id);
+                     email_ids.add(email_view.email.id);
 
                      // Since it can take some time for the new flags
                      // to round-trip back to ConversationViewer's
                      // signal handlers, mark as manually read here
-                     conversation_email.mark_manual_read();
+                     email_view.mark_manual_read();
                  }
              }
-        }
+            return true;
+        });
 
         if (email_ids.size > 0) {
             Geary.EmailFlags flags = new Geary.EmailFlags();
@@ -607,14 +626,10 @@ public class ConversationViewer : Gtk.Stack {
         ordered_matches.sort((a, b) => a.length - b.length);
 
         if (!cancellable.is_cancelled()) {
-            foreach (Geary.Email email in emails) {
-                ConversationEmail email_view = conversation_email_for_id(email.id);
-                email_view.primary_message
-                    .highlight_search_terms(search_matches);
-                foreach (ConversationMessage message_view in email_view.attached_messages) {
-                    message_view.highlight_search_terms(search_matches);
-                }
-            }
+            message_view_iterator().foreach((msg_view) => {
+                    msg_view.highlight_search_terms(search_matches);
+                    return true;
+                });
         }
     }
 
@@ -772,13 +787,10 @@ public class ConversationViewer : Gtk.Stack {
     private uint on_reset(uint state, uint event, void *user, Object? object) {
         //web_view.allow_collapsing(true);
 
-        foreach (Geary.Email email in emails) {
-            ConversationEmail email_view = conversation_email_for_id(email.id);
-            email_view.primary_message.unmark_search_terms();
-            foreach (ConversationMessage message_view in email_view.attached_messages) {
-                message_view.unmark_search_terms();
-            }
-        }
+        message_view_iterator().foreach((msg_view) => {
+                msg_view.unmark_search_terms();
+                return true;
+            });
 
         if (search_folder != null) {
             search_folder = null;


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