diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index 9d3c2080..31de05ea 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 action_accelerators = new Gee.HashMultiMap(); @@ -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 - // // 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); + // Step 1. - // const WebKit.ContextMenuAction[] spelling_actions = { - // WebKit.ContextMenuAction.SPELLING_GUESS, - // WebKit.ContextMenuAction.IGNORE_SPELLING, - // WebKit.ContextMenuAction.LEARN_SPELLING - // }; + 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, + }; - // if (!(action in spelling_actions)) - // context_menu.remove(item); - // } + Gee.List existing_spelling = + new Gee.LinkedList(); + Gee.List existing_text_entry = + new Gee.LinkedList(); - // // 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)); - // }); + 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 (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 2. - // context_menu.show_all(); - // update_actions(); - return false; + context_menu.remove_all(); + + // Step 3. + + 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 ae205e1b..8c7107cf 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 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 56f0a006..f9f7c64a 100644 --- a/ui/composer-menus.ui +++ b/ui/composer-menus.ui @@ -72,42 +72,60 @@ +
_Undo - cme.undo + cmp.undo _Redo - cme.redo + cmp.redo
-
+
Cu_t - cme.cut + cmp.cut _Copy - cme.copy - - - Copy _Link - cme.copy-link + cmp.copy _Paste - cme.paste + cmp.paste Paste _With Formatting - cme.paste-with-formatting + cmp.paste-with-formatting + +
+
+ + Cu_t + cmp.cut + + + _Copy + cmp.copy + + + _Paste + cmp.paste
Select _All - cme.select-all + cmp.select-all + +
+
+
+ + _Inspect… + cmp.open_inspector