[geary/wip/728002-webkit2: 79/96] Re-implement composer font family/size action state updating.



commit 859ea907e08221b42014ad23f2aab3910e042845
Author: Michael James Gratton <mike vee net>
Date:   Wed Jan 4 20:11:01 2017 +1100

    Re-implement composer font family/size action state updating.
    
    * src/client/composer/composer-web-view.vala (ComposerWebView): Add new
      ::cursor_style_changed signal, hook it up to the JS cursorStyleChanged
      message and interpret the raw results from the web view before passing
      it on.
    
    * src/client/composer/composer-widget.vala (ComposerWidget): Replace
      remainder of old ::update_actions method with a listener for
      ComposerWebView::cursor_style_changed. Reimplement in terms of that
      signal.
    
    * ui/composer-web-view.js: Keep track of font family and size changes,
      send a cursorStyleChanged message when they change.

 src/client/composer/composer-web-view.vala |   58 ++++++++++++++++++
 src/client/composer/composer-widget.vala   |   91 +++++++---------------------
 ui/composer-web-view.js                    |   27 ++++++++
 3 files changed, 106 insertions(+), 70 deletions(-)
---
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
index bfba08b..b470c59 100644
--- a/src/client/composer/composer-web-view.vala
+++ b/src/client/composer/composer-web-view.vala
@@ -13,6 +13,17 @@ public class ComposerWebView : ClientWebView {
 
 
     private const string COMMAND_STACK_CHANGED = "commandStackChanged";
+    private const string CURSOR_STYLE_CHANGED = "cursorStyleChanged";
+
+    private const string[] SANS_FAMILY_NAMES = {
+        "sans", "arial", "trebuchet", "helvetica"
+    };
+    private const string[] SERIF_FAMILY_NAMES = {
+        "serif", "georgia", "times"
+    };
+    private const string[] MONO_FAMILY_NAMES = {
+        "monospace", "courier", "console"
+    };
 
     private const string HTML_BODY = """
         <html><head><title></title>
@@ -61,6 +72,21 @@ public class ComposerWebView : ClientWebView {
         </body></html>""";
     private const string CURSOR = "<span id=\"cursormarker\"></span>";
 
+    private static Gee.HashMap<string,string> font_family_map =
+        new Gee.HashMap<string,string>();
+
+    static construct {
+        foreach (string name in SANS_FAMILY_NAMES) {
+            font_family_map["sans"] = name;
+        }
+        foreach (string name in SERIF_FAMILY_NAMES) {
+            font_family_map["serif"] = name;
+        }
+        foreach (string name in MONO_FAMILY_NAMES) {
+            font_family_map["monospace"] = name;
+        }
+    }
+
     private static WebKit.UserScript? app_script = null;
 
     public static void load_resources()
@@ -82,6 +108,10 @@ public class ComposerWebView : ClientWebView {
     /** Emitted when the web view's undo/redo stack has changed. */
     public signal void command_stack_changed(bool can_undo, bool can_redo);
 
+    /** Emitted when the style under the cursor has changed. */
+    public signal void cursor_style_changed(string face, uint size);
+
+
     public ComposerWebView(Configuration config) {
         base(config);
         this.user_content_manager.add_script(ComposerWebView.app_script);
@@ -100,7 +130,12 @@ public class ComposerWebView : ClientWebView {
                 }
             });
                     result.unref();
+        this.user_content_manager.script_message_received[CURSOR_STYLE_CHANGED].connect(
+            on_cursor_style_changed_message
+        );
+
         register_message_handler(COMMAND_STACK_CHANGED);
+        register_message_handler(CURSOR_STYLE_CHANGED);
     }
 
     /**
@@ -353,6 +388,29 @@ public class ComposerWebView : ClientWebView {
         return false;
     }
 
+    private void on_cursor_style_changed_message(WebKit.JavascriptResult result) {
+        try {
+            string[] values = WebKitUtil.to_string(result).split(",");
+            string view_name = values[0].down();
+            string? font_family = "sans";
+            foreach (string name in ComposerWebView.font_family_map.keys) {
+                if (name in view_name) {
+                    font_family = ComposerWebView.font_family_map[name];
+                    break;
+                }
+            }
+
+            uint font_size = 12;
+            values[1].scanf("%dpx", out font_size);
+
+            cursor_style_changed(font_family, font_size);
+        } catch (Geary.JS.Error err) {
+            debug("Could not get cursor style: %s", err.message);
+        } finally {
+            result.unref();
+        }
+    }
+
     // We really want to examine
     // Gdk.Keymap.get_default().get_modifier_state(), instead of
     // storing whether the shift key is down at each keypress, but it
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 6c53658..64b76ec 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -12,6 +12,8 @@ private errordomain AttachmentError {
 // The actual widget for sending messages. Should be put in a ComposerContainer
 [GtkTemplate (ui = "/org/gnome/Geary/composer-widget.ui")]
 public class ComposerWidget : Gtk.EventBox {
+
+
     public enum ComposeType {
         NEW_MESSAGE,
         REPLY,
@@ -475,8 +477,8 @@ public class ComposerWidget : Gtk.EventBox {
         this.editor.load_changed.connect(on_load_changed);
         this.editor.mouse_target_changed.connect(on_mouse_target_changed);
         this.editor.get_editor_state().notify["typing-attributes"].connect(on_typing_attributes_changed);
-        // this.editor.move_focus.connect(update_actions);
         this.editor.selection_changed.connect(on_selection_changed);
+        this.editor.cursor_style_changed.connect(on_cursor_style_changed);
         this.editor.key_press_event.connect(on_editor_key_press);
         //this.editor.user_changed_contents.connect(reset_draft_timer);
 
@@ -558,7 +560,6 @@ public class ComposerWidget : Gtk.EventBox {
         insert_action_group("cmp", this.actions);
         this.header.insert_action_group("cmh", this.actions);
 
-        update_actions();
         get_action(ACTION_UNDO).set_enabled(false);
         get_action(ACTION_REDO).set_enabled(false);
     }
@@ -799,11 +800,12 @@ public class ComposerWidget : Gtk.EventBox {
         // This is safe to call even when this connection hasn't been made.
         realize.disconnect(on_load_finished_and_realized);
 
-        update_actions();
-
-        this.actions.change_action_state(ACTION_SHOW_EXTENDED, false);
-        this.actions.change_action_state(ACTION_COMPOSE_AS_HTML,
-            GearyApplication.instance.config.compose_as_html);
+        this.actions.change_action_state(
+            ACTION_SHOW_EXTENDED, false
+        );
+        this.actions.change_action_state(
+            ACTION_COMPOSE_AS_HTML, this.config.compose_as_html
+        );
 
         if (can_delete_quote)
             this.editor.selection_changed.connect(
@@ -1847,8 +1849,6 @@ public class ComposerWidget : Gtk.EventBox {
     // This overrides the keypress handling for the *widget*; the WebView editor's keypress overrides
     // are handled by on_editor_key_press
     public override bool key_press_event(Gdk.EventKey event) {
-        update_actions();
-        
         switch (Gdk.keyval_name(event.keyval)) {
             case "Return":
             case "KP_Enter":
@@ -1860,7 +1860,7 @@ public class ComposerWidget : Gtk.EventBox {
                 }
             break;
         }
-        
+
         return base.key_press_event(event);
     }
 
@@ -2013,66 +2013,6 @@ public class ComposerWidget : Gtk.EventBox {
         return this.actions.lookup_action(action_name) as SimpleAction;
     }
 
-    /**
-     * Updates the states of the composer's actions and whether they should be enabled.
-     */
-    private void update_actions() {
-        // Basic editor commands
-        get_action(ACTION_UNDO).set_enabled(this.editor.can_undo());
-        get_action(ACTION_REDO).set_enabled(this.editor.can_redo());
-        get_action(ACTION_CUT).set_enabled(this.editor.can_cut_clipboard());
-        get_action(ACTION_COPY).set_enabled(this.editor.can_copy_clipboard());
-        get_action(ACTION_PASTE).set_enabled(this.editor.can_paste_clipboard());
-        get_action(ACTION_PASTE_WITH_FORMATTING).set_enabled(
-            this.editor.can_paste_clipboard() &&
-            this.editor.is_rich_text
-        );
-
-        // // Style formatting actions.
-        // WebKit.DOM.Document document = this.editor.get_dom_document();
-        // WebKit.DOM.DOMWindow window = document.get_default_view();
-        // WebKit.DOM.DOMSelection? selection = window.get_selection();
-        // if (selection == null)
-        //     return;
-
-        // get_action(ACTION_REMOVE_FORMAT).set_enabled(!selection.is_collapsed
-        //     && this.editor.is_rich_text);
-
-        // WebKit.DOM.Element? active = selection.focus_node as WebKit.DOM.Element;
-        // if (active == null && selection.focus_node != null)
-        //     active = selection.focus_node.get_parent_element();
-
-        // if (active != null) {
-        //     WebKit.DOM.CSSStyleDeclaration styles = window.get_computed_style(active, "");
-
-        //     // Font family.
-        //     string font_name = styles.get_property_value("font-family").down();
-        //     if (font_name.contains("sans") ||
-        //         font_name.contains("arial") ||
-        //         font_name.contains("trebuchet") ||
-        //         font_name.contains("helvetica"))
-        //         this.actions.change_action_state(ACTION_FONT_FAMILY, "sans");
-        //     else if (font_name.contains("serif") ||
-        //         font_name.contains("georgia") ||
-        //         font_name.contains("times"))
-        //         this.actions.change_action_state(ACTION_FONT_FAMILY, "serif");
-        //     else if (font_name.contains("monospace") ||
-        //         font_name.contains("courier") ||
-        //         font_name.contains("console"))
-        //         this.actions.change_action_state(ACTION_FONT_FAMILY, "monospace");
-
-        //     // Font size.
-        //     int font_size;
-        //     styles.get_property_value("font-size").scanf("%dpx", out font_size);
-        //     if (font_size < 11)
-        //         this.actions.change_action_state(ACTION_FONT_SIZE, "small");
-        //     else if (font_size > 20)
-        //         this.actions.change_action_state(ACTION_FONT_SIZE, "large");
-        //     else
-        //         this.actions.change_action_state(ACTION_FONT_SIZE, "medium");
-        // }
-    }
-
     private bool add_account_emails_to_from_list(Geary.Account other_account, bool set_active = false) {
         Geary.RFC822.MailboxAddresses primary_address = new Geary.RFC822.MailboxAddresses.single(
             other_account.information.primary_mailbox);
@@ -2246,6 +2186,17 @@ public class ComposerWidget : Gtk.EventBox {
         );
     }
 
+    private void on_cursor_style_changed(string font_family, uint font_size) {
+        this.actions.change_action_state(ACTION_FONT_FAMILY, font_family);
+
+        if (font_size < 11)
+            this.actions.change_action_state(ACTION_FONT_SIZE, "small");
+        else if (font_size > 20)
+            this.actions.change_action_state(ACTION_FONT_SIZE, "large");
+        else
+            this.actions.change_action_state(ACTION_FONT_SIZE, "medium");
+    }
+
     private void on_typing_attributes_changed() {
         uint mask = this.editor.get_editor_state().get_typing_attributes();
         this.actions.change_action_state(
diff --git a/ui/composer-web-view.js b/ui/composer-web-view.js
index 62a648d..e54dcce 100644
--- a/ui/composer-web-view.js
+++ b/ui/composer-web-view.js
@@ -27,6 +27,9 @@ ComposerPageState.prototype = {
         this.undoEnabled = false;
         this.redoEnabled = false;
 
+        this.cursorFontFamily = null;
+        this.cursorFontSize = null;
+
         let state = this;
 
         document.addEventListener("click", function(e) {
@@ -142,6 +145,30 @@ ComposerPageState.prototype = {
     },
     linkClicked: function(element) {
         window.getSelection().selectAllChildren(element);
+    },
+    selectionChanged: function() {
+        PageState.prototype.selectionChanged.apply(this, []);
+
+        let selection = window.getSelection();
+        let active = selection.focusNode;
+        if (active != null && active.nodeType != Node.ELEMENT_TYPE) {
+            active = active.parentNode;
+        }
+
+        if (active != null) {
+            let styles = window.getComputedStyle(active);
+            let fontFamily = styles.getPropertyValue("font-family");
+            let fontSize = styles.getPropertyValue("font-size");
+
+            if (fontFamily != this.cursorFontFamily ||
+                fontSize != this.cursorFontSize) {
+                this.cursorFontFamily = fontFamily;
+                this.cursorFontSize = fontSize;
+                window.webkit.messageHandlers.cursorStyleChanged.postMessage(
+                    fontFamily + "," + fontSize
+                );
+            }
+        }
     }
 };
 


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