[geary/mjog/misc-fixes: 25/27] Clean up EmailEntry API



commit b3fa1446c195205941ef76e1f519146b60fd3010
Author: Michael Gratton <mike vee net>
Date:   Sat Jan 25 16:48:47 2020 +1100

    Clean up EmailEntry API
    
    Move into composer namespace and rename to match. Update API for
    consistency with style guide. Remove uneeded fields and clarify when
    ::modified is true. Fix call sites.

 po/POTFILES.in                                |   2 +-
 src/client/composer/composer-email-entry.vala | 113 ++++++++++++++++++++++++++
 src/client/composer/composer-widget.vala      |  48 ++++++-----
 src/client/composer/email-entry.vala          | 106 ------------------------
 src/client/meson.build                        |   2 +-
 5 files changed, 138 insertions(+), 133 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index add1424e..4cf10a10 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -51,6 +51,7 @@ src/client/components/status-bar.vala
 src/client/components/stock.vala
 src/client/composer/composer-box.vala
 src/client/composer/composer-container.vala
+src/client/composer/composer-email-entry.vala
 src/client/composer/composer-embed.vala
 src/client/composer/composer-headerbar.vala
 src/client/composer/composer-link-popover.vala
@@ -58,7 +59,6 @@ src/client/composer/composer-web-view.vala
 src/client/composer/composer-widget.vala
 src/client/composer/composer-window.vala
 src/client/composer/contact-entry-completion.vala
-src/client/composer/email-entry.vala
 src/client/composer/spell-check-popover.vala
 src/client/conversation-list/conversation-list-cell-renderer.vala
 src/client/conversation-list/conversation-list-store.vala
diff --git a/src/client/composer/composer-email-entry.vala b/src/client/composer/composer-email-entry.vala
new file mode 100644
index 00000000..9502fb9a
--- /dev/null
+++ b/src/client/composer/composer-email-entry.vala
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2020 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+/**
+ * A GTK entry for entering email addresses.
+ */
+public class Composer.EmailEntry : Gtk.Entry {
+
+    /** The entry's list of possibly valid email addresses. */
+    public Geary.RFC822.MailboxAddresses addresses {
+        get { return this._addresses; }
+        set {
+            this._addresses = value;
+            validate_addresses();
+            this.is_modified = false;
+            this.text = value.to_full_display();
+        }
+    }
+    private Geary.RFC822.MailboxAddresses _addresses = new Geary.RFC822.MailboxAddresses();
+
+    /** Determines if the entry contains only valid email addresses. */
+    public bool is_valid { get; private set; default = false; }
+
+    /** Determines if the entry contains any email addresses. */
+    public bool is_empty {
+        get {
+            return this._addresses.is_empty;
+        }
+    }
+
+    /**
+     * Determines if the entry has been modified.
+     *
+     * The entry is considered to be modified only if the text has
+     * been changed after it as been constructed or if modified after
+     * setting {@link addresses}.
+     */
+    public bool is_modified { get; private set; default = false; }
+
+    private weak Composer.Widget composer;
+
+
+    public EmailEntry(Composer.Widget composer) {
+        changed.connect(on_changed);
+        key_press_event.connect(on_key_press);
+        this.composer = composer;
+        show();
+    }
+
+    /** Marks the entry as being modified. */
+    public void set_modified() {
+        this.is_modified = true;
+    }
+
+    private void validate_addresses() {
+        bool is_valid = !this.addresses.is_empty;
+        foreach (Geary.RFC822.MailboxAddress address in this.addresses) {
+            if (!address.is_valid()) {
+                is_valid = false;
+                return;
+            }
+        }
+        this.is_valid = is_valid;
+    }
+
+    private void on_changed() {
+        this.is_modified = true;
+
+        ContactEntryCompletion? completion =
+            get_completion() as ContactEntryCompletion;
+        if (completion != null) {
+            completion.update_model();
+        }
+
+        if (Geary.String.is_empty(text.strip())) {
+            this.addresses = new Geary.RFC822.MailboxAddresses();
+            this.is_valid = false;
+        } else {
+            this.addresses =
+                new Geary.RFC822.MailboxAddresses.from_rfc822_string(text);
+            this.is_valid = true;
+        }
+    }
+
+    private bool on_key_press(Gtk.Widget widget, Gdk.EventKey event) {
+        bool ret = Gdk.EVENT_PROPAGATE;
+        if (event.keyval == Gdk.Key.Tab) {
+            ContactEntryCompletion? completion = (
+                get_completion() as ContactEntryCompletion
+            );
+            if (completion != null) {
+                completion.trigger_selection();
+                composer.child_focus(Gtk.DirectionType.TAB_FORWARD);
+                ret = Gdk.EVENT_STOP;
+            }
+        } else {
+            // Keyboard shortcuts for undo/redo won't work when the
+            // completion UI is visible unless we explicitly check for
+            // them there. This may be related to the
+            // single-key-shortcut handling hack in the MainWindow.
+            Gtk.Window? window = get_toplevel() as Gtk.Window;
+            if (window != null) {
+                ret = window.activate_key(event);
+            }
+        }
+        return ret;
+    }
+}
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index d935ca46..95513538 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -255,10 +255,10 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
     /** Determines if the composer is completely empty. */
     public bool is_blank {
         get {
-            return this.to_entry.empty
-                && this.cc_entry.empty
-                && this.bcc_entry.empty
-                && this.reply_to_entry.empty
+            return this.to_entry.is_empty
+                && this.cc_entry.is_empty
+                && this.bcc_entry.is_empty
+                && this.reply_to_entry.is_empty
                 && this.subject_entry.buffer.length == 0
                 && this.editor.is_empty
                 && this.attached_files.size == 0;
@@ -1017,29 +1017,28 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         else
             this.compose_type = ComposeType.REPLY_ALL;
 
-        this.to_entry.modified = this.cc_entry.modified = this.bcc_entry.modified = false;
         if (!to_entry.addresses.equal_to(reply_to_addresses))
-            this.to_entry.modified = true;
+            this.to_entry.set_modified();
         if (cc != "" && !cc_entry.addresses.equal_to(reply_cc_addresses))
-            this.cc_entry.modified = true;
+            this.cc_entry.set_modified();
         if (bcc != "")
-            this.bcc_entry.modified = true;
+            this.bcc_entry.set_modified();
 
         // We're in compact inline mode, but there are modified email
         // addresses, so set us to use plain inline mode instead so
         // the modified addresses can be seen. If there are CC
         if (this.current_mode == INLINE_COMPACT && (
-                this.to_entry.modified ||
-                this.cc_entry.modified ||
-                this.bcc_entry.modified ||
-                this.reply_to_entry.modified)) {
+                this.to_entry.is_modified ||
+                this.cc_entry.is_modified ||
+                this.bcc_entry.is_modified ||
+                this.reply_to_entry.is_modified)) {
             set_mode(INLINE);
         }
 
         // If there's a modified header that would normally be hidden,
         // show full fields.
-        if (this.bcc_entry.modified ||
-            this.reply_to_entry.modified) {
+        if (this.bcc_entry.is_modified ||
+            this.reply_to_entry.is_modified) {
             this.editor_actions.change_action_state(
                 ACTION_SHOW_EXTENDED_HEADERS, true
             );
@@ -1402,7 +1401,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         if (!modify_headers)
             return;
 
-        bool recipients_modified = this.to_entry.modified || this.cc_entry.modified || 
this.bcc_entry.modified;
+        bool recipients_modified = this.to_entry.is_modified || this.cc_entry.is_modified || 
this.bcc_entry.is_modified;
         if (!recipients_modified) {
             if (type == ComposeType.REPLY || type == ComposeType.REPLY_ALL)
                 this.to_entry.addresses = Geary.RFC822.Utils.merge_addresses(to_entry.addresses,
@@ -1414,7 +1413,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
             else
                 this.cc_entry.addresses = Geary.RFC822.Utils.remove_addresses(this.cc_entry.addresses,
                     this.to_entry.addresses);
-            this.to_entry.modified = this.cc_entry.modified = false;
         }
 
         if (referred.message_id != null) {
@@ -1953,16 +1951,16 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         // To must be valid (and hence non-empty), the other email
         // fields must be either empty or valid.
         get_action(ACTION_SEND).set_enabled(
-            this.to_entry.valid &&
-            (this.cc_entry.empty || this.cc_entry.valid) &&
-            (this.bcc_entry.empty || this.bcc_entry.valid) &&
-            (this.reply_to_entry.empty || this.reply_to_entry.valid)
+            this.to_entry.is_valid &&
+            (this.cc_entry.is_empty || this.cc_entry.is_valid) &&
+            (this.bcc_entry.is_empty || this.bcc_entry.is_valid) &&
+            (this.reply_to_entry.is_empty || this.reply_to_entry.is_valid)
         );
     }
 
     private void set_compact_header_recipients() {
-        bool tocc = !this.to_entry.empty && !this.cc_entry.empty,
-            ccbcc = !(this.to_entry.empty && this.cc_entry.empty) && !this.bcc_entry.empty;
+        bool tocc = !this.to_entry.is_empty && !this.cc_entry.is_empty,
+            ccbcc = !(this.to_entry.is_empty && this.cc_entry.is_empty) && !this.bcc_entry.is_empty;
         string label = this.to_entry.buffer.text + (tocc ? ", " : "")
             + this.cc_entry.buffer.text + (ccbcc ? ", " : "") + this.bcc_entry.buffer.text;
         StringBuilder tooltip = new StringBuilder();
@@ -2145,9 +2143,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
     }
 
     private void update_extended_headers(bool reorder=true) {
-        bool cc = this.cc_entry.addresses != null;
-        bool bcc = this.bcc_entry.addresses != null;
-        bool reply_to = this.reply_to_entry.addresses != null;
+        bool cc = !this.cc_entry.is_empty;
+        bool bcc = !this.bcc_entry.is_empty;
+        bool reply_to = !this.reply_to_entry.is_empty;
 
         if (reorder) {
             if (cc) {
diff --git a/src/client/meson.build b/src/client/meson.build
index bb61d9f5..35c876bf 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -53,6 +53,7 @@ geary_client_vala_sources = files(
 
   'composer/composer-box.vala',
   'composer/composer-container.vala',
+  'composer/composer-email-entry.vala',
   'composer/composer-embed.vala',
   'composer/composer-headerbar.vala',
   'composer/composer-link-popover.vala',
@@ -60,7 +61,6 @@ geary_client_vala_sources = files(
   'composer/composer-widget.vala',
   'composer/composer-window.vala',
   'composer/contact-entry-completion.vala',
-  'composer/email-entry.vala',
   'composer/spell-check-popover.vala',
 
   'conversation-list/conversation-list-cell-renderer.vala',


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