[geary/bug/728002-webkit2: 65/140] Re-enable custom composer context menu, add WK text entry items to it.



commit 20db6e57ddf4c6feef7ef5deb80fc0c66daff319
Author: Michael James Gratton <mike vee net>
Date:   Wed Jan 4 13:54:07 2017 +1100

    Re-enable custom composer context menu, add WK text entry items to it.
    
    * src/client/composer/composer-widget.vala
      (ComposerWidget::action_entries): Add an entry for the inspector so it
      can be loaded via the context model in the same way as other items.
      (ComposerWidget::context_menu_*): Keep track of a number of the context
      menu's sections, so we can selectively include them in the WK context
      menu.
      (ComposerWidget::on_context_menu): Re-implement to work wth the WK2
      context menu model, which annoyingly doesn't even extend any of the
      GtkMenu infrastrcuture.
    
    * src/client/util/util-gtk.vala (menu_foreach): Pass the action
      target through to the loop's delegate, it's a bit more useful for
      dealing with the WK2 model.
      (add_g_menu_to_gtk_menu): Removed, WebKitContextMenu doesn't extend
      Gtk.Menu any longer so this is is no longer needed.
    
    * ui/composer-menus.ui: Reoganise to use standard composer action
      prefix. Duplicate rich and plain text clipboard sections so they can
      just be selectively enabled. Include dummy sections for WK items to
      specify where they are located in the menu, and a section for the
      inspector.

 src/client/composer/composer-widget.vala |  130 +++++++++++++++++++++---------
 src/client/util/util-gtk.vala            |   51 ++----------
 ui/composer-menus.ui                     |   42 +++++++---
 3 files changed, 129 insertions(+), 94 deletions(-)
---
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 9d3c208..31de05e 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -77,6 +77,7 @@ public class ComposerWidget : Gtk.EventBox {
     private const string ACTION_ADD_ATTACHMENT = "add-attachment";
     private const string ACTION_ADD_ORIGINAL_ATTACHMENTS = "add-original-attachments";
     private const string ACTION_SELECT_DICTIONARY = "select-dictionary";
+    private const string ACTION_OPEN_INSPECTOR = "open_inspector";
 
     private const string[] html_actions = {
         ACTION_BOLD, ACTION_ITALIC, ACTION_UNDERLINE, ACTION_STRIKETHROUGH, ACTION_FONT_SIZE,
@@ -118,6 +119,7 @@ public class ComposerWidget : Gtk.EventBox {
         {ACTION_ADD_ATTACHMENT,           on_add_attachment                                                  
  },
         {ACTION_ADD_ORIGINAL_ATTACHMENTS, on_pending_attachments                                             
  },
         {ACTION_SELECT_DICTIONARY,        on_select_dictionary                                               
  },
+        {ACTION_OPEN_INSPECTOR,           on_open_inspector                                                  
  },
     };
 
     public static Gee.MultiMap<string, string> action_accelerators = new Gee.HashMultiMap<string, string>();
@@ -298,7 +300,13 @@ public class ComposerWidget : Gtk.EventBox {
 
     private Menu html_menu;
     private Menu plain_menu;
+
     private Menu context_menu_model;
+    private Menu context_menu_rich_text;
+    private Menu context_menu_plain_text;
+    private Menu context_menu_webkit_spelling;
+    private Menu context_menu_webkit_text_entry;
+    private Menu context_menu_inspector;
 
     private SpellCheckPopover? spell_check_popover = null;
     private string? hover_url = null;
@@ -401,6 +409,11 @@ public class ComposerWidget : Gtk.EventBox {
         this.html_menu = (Menu) builder.get_object("html_menu_model");
         this.plain_menu = (Menu) builder.get_object("plain_menu_model");
         this.context_menu_model = (Menu) builder.get_object("context_menu_model");
+        this.context_menu_rich_text = (Menu) builder.get_object("context_menu_rich_text");
+        this.context_menu_plain_text = (Menu) builder.get_object("context_menu_plain_text");
+        this.context_menu_inspector = (Menu) builder.get_object("context_menu_inspector");
+        this.context_menu_webkit_spelling = (Menu) builder.get_object("context_menu_webkit_spelling");
+        this.context_menu_webkit_text_entry = (Menu) builder.get_object("context_menu_webkit_text_entry");
 
         this.subject_entry.bind_property("text", this, "window-title", BindingFlags.SYNC_CREATE,
             (binding, source_value, ref target_value) => {
@@ -1843,53 +1856,88 @@ public class ComposerWidget : Gtk.EventBox {
     }
 
     private bool on_context_menu(WebKit.WebView view,
-                                 WebKit.ContextMenu default_menu,
+                                 WebKit.ContextMenu context_menu,
                                  Gdk.Event event,
                                  WebKit.HitTestResult hit_test_result) {
-        // Gtk.Menu context_menu = (Gtk.Menu) default_menu;
+        // This is a three step process:
+        // 1. Work out what existing menu items exist that we want to keep
+        // 2. Clear the existing menu
+        // 3. Rebuild it based on our GMenu specification
+
+        // Step 1.
+
+        const WebKit.ContextMenuAction[] SPELLING_ACTIONS = {
+            WebKit.ContextMenuAction.SPELLING_GUESS,
+            WebKit.ContextMenuAction.NO_GUESSES_FOUND,
+            WebKit.ContextMenuAction.IGNORE_SPELLING,
+            WebKit.ContextMenuAction.IGNORE_GRAMMAR,
+            WebKit.ContextMenuAction.LEARN_SPELLING,
+        };
+        const WebKit.ContextMenuAction[] TEXT_INPUT_ACTIONS = {
+            WebKit.ContextMenuAction.INPUT_METHODS,
+            WebKit.ContextMenuAction.UNICODE,
+        };
 
-        // // Keep the spelling menu items
-        // foreach (weak Gtk.Widget child in context_menu.get_children()) {
-        //     Gtk.MenuItem item = (Gtk.MenuItem) child;
-        //     WebKit.ContextMenuAction action = WebKit.context_menu_item_get_action(item);
+        Gee.List<WebKit.ContextMenuItem> existing_spelling =
+            new Gee.LinkedList<WebKit.ContextMenuItem>();
+        Gee.List<WebKit.ContextMenuItem> existing_text_entry =
+            new Gee.LinkedList<WebKit.ContextMenuItem>();
 
-        //     const WebKit.ContextMenuAction[] spelling_actions = {
-        //         WebKit.ContextMenuAction.SPELLING_GUESS,
-        //         WebKit.ContextMenuAction.IGNORE_SPELLING,
-        //         WebKit.ContextMenuAction.LEARN_SPELLING
-        //     };
+        foreach (WebKit.ContextMenuItem item in context_menu.get_items()) {
+            if (item.get_stock_action() in SPELLING_ACTIONS) {
+                existing_spelling.add(item);
+            } else if (item.get_stock_action() in TEXT_INPUT_ACTIONS) {
+                existing_text_entry.add(item);
+            }
+        }
 
-        //     if (!(action in spelling_actions))
-        //         context_menu.remove(item);
-        // }
+        // Step 2.
 
-        // // Add our own Menu (but don't add formatting actions if they are disabled).
-        // context_menu.insert_action_group("cme", this.actions);
-        // GtkUtil.add_g_menu_to_gtk_menu(context_menu, context_menu_model, (label, detailed_action_name) => 
{
-        //     string action_name;
-        //     Variant? target;
-        //     try {
-        //         Action.parse_detailed_name(detailed_action_name, out action_name, out target);
-        //         if ("." in action_name) // Remove possible prefixes
-        //             action_name = action_name.split(".")[1];
-        //     } catch (GLib.Error e) {
-        //         debug("Couldn't parse action \"%s\" in context menu".printf(detailed_action_name));
-        //     }
-        //     return !(action_name in html_actions) || (this.actions.get_action_enabled(action_name));
-        // });
+        context_menu.remove_all();
 
-        // if (Args.inspector) {
-        //     Gtk.MenuItem inspect_item = new Gtk.MenuItem.with_mnemonic(_("_Inspect"));
-        //     inspect_item.activate.connect(() => {
-        //             this.editor.get_inspector().show();
-        //         });
-        //     context_menu.append(new Gtk.SeparatorMenuItem());
-        //     context_menu.append(inspect_item);
-        // }
+        // Step 3.
 
-        // context_menu.show_all();
-        // update_actions();
-        return false;
+        GtkUtil.menu_foreach(context_menu_model, (label, name, target, section) => {
+                if (context_menu.last() != null) {
+                    context_menu.append(new WebKit.ContextMenuItem.separator());
+                }
+
+                if (section == this.context_menu_webkit_spelling) {
+                    foreach (WebKit.ContextMenuItem item in existing_spelling)
+                        context_menu.append(item);
+                } else if (section == this.context_menu_webkit_text_entry) {
+                    foreach (WebKit.ContextMenuItem item in existing_text_entry)
+                        context_menu.append(item);
+                } else if (section == this.context_menu_rich_text) {
+                    if (this.editor.is_rich_text)
+                        append_menu_section(context_menu, section);
+                } else if (section == this.context_menu_plain_text) {
+                    if (!this.editor.is_rich_text)
+                        append_menu_section(context_menu, section);
+                } else if (section == this.context_menu_inspector) {
+                    if (Args.inspector)
+                        append_menu_section(context_menu, section);
+                } else {
+                    append_menu_section(context_menu, section);
+                }
+            });
+
+        return Gdk.EVENT_PROPAGATE;
+    }
+
+    private inline void append_menu_section(WebKit.ContextMenu context_menu,
+                                            Menu section) {
+        GtkUtil.menu_foreach(section, (label, name, target, section) => {
+                if ("." in name)
+                    name = name.split(".")[1];
+
+                Gtk.Action action = new Gtk.Action(name, label, null, null);
+                action.set_sensitive(get_action(name).enabled);
+                action.activate.connect((action) => {
+                        this.actions.activate_action(name, target);
+                    });
+                context_menu.append(new WebKit.ContextMenuItem(action));
+            });
     }
 
     private void on_select_dictionary(SimpleAction action, Variant? param) {
@@ -2243,4 +2291,8 @@ public class ComposerWidget : Gtk.EventBox {
         link_dialog("http://";);
     }
 
+    private void on_open_inspector(SimpleAction action, Variant? param) {
+        this.editor.get_inspector().show();
+    }
+
 }
diff --git a/src/client/util/util-gtk.vala b/src/client/util/util-gtk.vala
index ae205e1..8c7107c 100644
--- a/src/client/util/util-gtk.vala
+++ b/src/client/util/util-gtk.vala
@@ -146,61 +146,26 @@ void menu_foreach(Menu menu, MenuForeachFunc foreach_func) {
         Variant? label = menu.get_item_attribute_value(i, Menu.ATTRIBUTE_LABEL, VariantType.STRING);
         Variant? action_name = menu.get_item_attribute_value(i, Menu.ATTRIBUTE_ACTION, VariantType.STRING);
         Variant? action_target = menu.get_item_attribute_value(i, Menu.ATTRIBUTE_TARGET, VariantType.STRING);
-        string detailed_action_name = null;
-        if (action_name != null)
-            detailed_action_name = Action.print_detailed_name(action_name.get_string(), action_target);
 
         // Check if the child is a section
         Menu? section = (Menu) menu.get_item_link(i, Menu.LINK_SECTION);
 
         // Callback
-        foreach_func((label != null) ? label.get_string() : null
-                     , detailed_action_name
-                     , section);
+        foreach_func((label != null) ? label.get_string() : null,
+                     (action_name != null) ? action_name.get_string() : null,
+                     action_target,
+                     section);
     }
 }
 
 /*
  * Used for menu_foreach()
+ * @param id - The id if one was set
  * @param label - The label if one was set
- * @param detailed_action_name - The action if it was set
+ * @param action_name - The action name, if set
+ * @param action_target - The action target, if set
  * @param section - If the item represents a section, this will return that section (or null otherwise)
  */
-delegate void MenuForeachFunc(string? label, string? detailed_action_name, Menu? section);
-
-/**
- * Adds the entries of a GLib.Menu to a Gtk.Menu
- * @param gtk_menu - The Gtk.Menu to add entries to.
- * @param g_menu - The Menu whose entries should be added
- * @param filter - If this function returns false for a menu item, it will not be added to the menu
- */
-void add_g_menu_to_gtk_menu(Gtk.Menu gtk_menu, Menu g_menu, MenuItemFilterFunc filter) {
-    menu_foreach(g_menu, (label, action_name, section) => {
-        List<weak Gtk.Widget> children = gtk_menu.get_children();
-        weak Gtk.Widget? last_child = (children.length() > 0) ? children.last().data : null;
-
-        if (section != null) {
-            // Section. Set separators (without getting double separators)
-            if ((children.length() > 0) && ((last_child as Gtk.SeparatorMenuItem) == null))
-                gtk_menu.add(new Gtk.SeparatorMenuItem());
-
-            add_g_menu_to_gtk_menu(gtk_menu, section, filter);
-
-            if ((children.length() > 0) && ((last_child as Gtk.SeparatorMenuItem) == null))
-                gtk_menu.add(new Gtk.SeparatorMenuItem());
-        } else {
-            // Regular menu-item
-            if (filter(label, action_name) && label != null) {
-                Gtk.MenuItem item = new Gtk.MenuItem.with_mnemonic(label);
-                if (action_name != null)
-                    item.set_detailed_action_name(action_name);
-                gtk_menu.add(item);
-            }
-        }
-    });
-}
-
-// Used for add_g_menu_to_gtk_menu()
-delegate bool MenuItemFilterFunc(string? label, string? detailed_action_name);
+delegate void MenuForeachFunc(string? label, string? action_name, Variant? target, Menu? section);
 
 }
diff --git a/ui/composer-menus.ui b/ui/composer-menus.ui
index 56f0a00..f9f7c64 100644
--- a/ui/composer-menus.ui
+++ b/ui/composer-menus.ui
@@ -72,42 +72,60 @@
   </menu>
 
   <menu id="context_menu_model">
+    <section id="context_menu_webkit_spelling"/>
     <section>
       <item>
         <attribute name="label" translatable="yes">_Undo</attribute>
-        <attribute name="action">cme.undo</attribute>
+        <attribute name="action">cmp.undo</attribute>
       </item>
       <item>
         <attribute name="label" translatable="yes">_Redo</attribute>
-        <attribute name="action">cme.redo</attribute>
+        <attribute name="action">cmp.redo</attribute>
       </item>
     </section>
-    <section>
+    <section id="context_menu_rich_text">
       <item>
         <attribute name="label" translatable="yes">Cu_t</attribute>
-        <attribute name="action">cme.cut</attribute>
+        <attribute name="action">cmp.cut</attribute>
       </item>
       <item>
         <attribute name="label" translatable="yes">_Copy</attribute>
-        <attribute name="action">cme.copy</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">Copy _Link</attribute>
-        <attribute name="action">cme.copy-link</attribute>
+        <attribute name="action">cmp.copy</attribute>
       </item>
       <item>
         <attribute name="label" translatable="yes">_Paste</attribute>
-        <attribute name="action">cme.paste</attribute>
+        <attribute name="action">cmp.paste</attribute>
       </item>
       <item>
         <attribute name="label" translatable="yes" context="Clipboard paste with rich text">Paste _With 
Formatting</attribute>
-        <attribute name="action">cme.paste-with-formatting</attribute>
+        <attribute name="action">cmp.paste-with-formatting</attribute>
+      </item>
+    </section>
+    <section id="context_menu_plain_text">
+      <item>
+        <attribute name="label" translatable="yes">Cu_t</attribute>
+        <attribute name="action">cmp.cut</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Copy</attribute>
+        <attribute name="action">cmp.copy</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Paste</attribute>
+        <attribute name="action">cmp.paste</attribute>
       </item>
     </section>
     <section>
       <item>
         <attribute name="label" translatable="yes">Select _All</attribute>
-        <attribute name="action">cme.select-all</attribute>
+        <attribute name="action">cmp.select-all</attribute>
+      </item>
+    </section>
+    <section id="context_menu_webkit_text_entry"/>
+    <section id="context_menu_inspector">
+      <item>
+        <attribute name="label" translatable="yes">_Inspect…</attribute>
+        <attribute name="action">cmp.open_inspector</attribute>
       </item>
     </section>
   </menu>


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