[evolution/wip/webkit-composer: 102/372] Initial support for custom context menu



commit d60525f53afac23e66dd2bceddef5d2e69eac532
Author: Dan Vrátil <dvratil redhat com>
Date:   Mon Aug 13 14:45:42 2012 +0200

    Initial support for custom context menu

 e-util/e-editor-widget.c |   41 +++++++++++
 e-util/e-editor-widget.h |    5 +-
 e-util/e-editor.c        |  166 ++++++++++++++++++++++++++++++++++++++++++++++
 e-util/e-editor.h        |    3 +
 4 files changed, 214 insertions(+), 1 deletions(-)
---
diff --git a/e-util/e-editor-widget.c b/e-util/e-editor-widget.c
index 6b648c0..eb6d78d 100644
--- a/e-util/e-editor-widget.c
+++ b/e-util/e-editor-widget.c
@@ -25,6 +25,7 @@
 #include "e-emoticon-chooser.h"
 
 #include <e-util/e-util.h>
+#include <e-util/e-marshal.h>
 #include <glib/gi18n-lib.h>
 #include <gdk/gdkkeysyms.h>
 
@@ -70,6 +71,13 @@ enum {
        PROP_CAN_UNDO
 };
 
+enum {
+       POPUP_EVENT,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 static WebKitDOMRange *
 editor_widget_get_dom_range (EEditorWidget *widget)
 {
@@ -152,6 +160,28 @@ editor_widget_selection_changed_cb (EEditorWidget *widget,
        }
 }
 
+static gboolean
+editor_widget_button_press_event (GtkWidget *gtk_widget,
+                                 GdkEventButton *event)
+{
+       gboolean event_handled;
+
+       if (event->button != 3) {
+               event_handled = FALSE;
+       } else {
+               g_signal_emit (
+                       gtk_widget, signals[POPUP_EVENT],
+                       0, event, &event_handled);
+       }
+
+       if (event_handled) {
+               return TRUE;
+       }
+
+       /* Chain up to parent implementation */
+       return GTK_WIDGET_CLASS (e_editor_widget_parent_class)->button_press_event (gtk_widget, event);
+}
+
 /* Based on original use_pictograms() from GtkHTML */
 static const gchar *emoticons_chars =
        /*  0 */ "DO)(|/PQ*!"
@@ -476,6 +506,7 @@ e_editor_widget_class_init (EEditorWidgetClass *klass)
        object_class->finalize = e_editor_widget_finalize;
 
        widget_class = GTK_WIDGET_CLASS (klass);
+       widget_class->button_press_event = editor_widget_button_press_event;
        widget_class->key_release_event = editor_widget_key_release_event;
 
        klass->paste_clipboard_quoted = editor_widget_paste_clipboard_quoted;
@@ -585,6 +616,16 @@ e_editor_widget_class_init (EEditorWidgetClass *klass)
                        NULL,
                        FALSE,
                        G_PARAM_READABLE));
+
+       signals[POPUP_EVENT] = g_signal_new (
+               "popup-event",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EEditorWidgetClass, popup_event),
+               g_signal_accumulator_true_handled, NULL,
+               e_marshal_BOOLEAN__BOXED,
+               G_TYPE_BOOLEAN, 1,
+               GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 }
 
 static void
diff --git a/e-util/e-editor-widget.h b/e-util/e-editor-widget.h
index 487c1a0..1f08c4b 100644
--- a/e-util/e-editor-widget.h
+++ b/e-util/e-editor-widget.h
@@ -73,7 +73,10 @@ struct _EEditorWidget {
 struct _EEditorWidgetClass {
        WebKitWebViewClass parent_class;
 
-       void    (*paste_clipboard_quoted)       (EEditorWidget *widget);
+       void            (*paste_clipboard_quoted)       (EEditorWidget *widget);
+
+       gboolean        (*popup_event)                  (EEditorWidget *widget,
+                                                        GdkEventButton *event);
 };
 
 GType          e_editor_widget_get_type        (void);
diff --git a/e-util/e-editor.c b/e-util/e-editor.c
index 238f166..892623f 100644
--- a/e-util/e-editor.c
+++ b/e-util/e-editor.c
@@ -21,6 +21,7 @@
 
 #include "e-editor.h"
 #include "e-editor-private.h"
+#include "e-editor-utils.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -34,6 +35,157 @@ enum {
        PROP_FILENAME
 };
 
+enum {
+       UPDATE_ACTIONS,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+editor_update_actions (EEditor *editor,
+                      GdkEventButton *event)
+{
+       WebKitWebView *webview;
+       WebKitHitTestResult *hit_test;
+       WebKitHitTestResultContext context;
+       WebKitDOMNode *node;
+       EEditorWidget *widget;
+       GtkUIManager *manager;
+       GtkActionGroup *action_group;
+       GList *list;
+       gboolean visible;
+       guint merge_id;
+
+       widget = e_editor_get_editor_widget (editor);
+       webview = WEBKIT_WEB_VIEW (widget);
+       manager = e_editor_get_ui_manager (editor);
+
+       /* Update context menu item visibility. */
+       hit_test = webkit_web_view_get_hit_test_result (webview, event);
+       g_object_get (
+               G_OBJECT (hit_test),
+               "context", &context,
+               "inner-node", &node, NULL);
+
+       visible = (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_IMAGE), visible);
+
+       visible = (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_LINK), visible);
+
+       visible = (WEBKIT_DOM_IS_HTMLHR_ELEMENT (node));
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_RULE), visible);
+
+       visible = (webkit_dom_node_get_node_type (node) == 3);
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_TEXT), visible);
+
+       visible =
+               gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_IMAGE)) ||
+               gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_LINK)) ||
+               gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_TEXT));
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_PARAGRAPH), visible);
+
+       /* Set to visible if any of these are true:
+        *   - Selection is active and contains a link.
+        *   - Cursor is on a link.
+        *   - Cursor is on an image that has a URL or target.
+        */
+       visible = (e_editor_dom_node_get_parent_element (
+                       node, WEBKIT_TYPE_DOM_HTML_ANCHOR_ELEMENT) != NULL);
+       gtk_action_set_visible (ACTION (CONTEXT_REMOVE_LINK), visible);
+
+
+       visible = (e_editor_dom_node_get_parent_element (
+                       node, WEBKIT_TYPE_DOM_HTML_TABLE_CELL_ELEMENT) != NULL);
+       gtk_action_set_visible (ACTION (CONTEXT_DELETE_CELL), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_DELETE_COLUMN), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_DELETE_ROW), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_DELETE_TABLE), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_AFTER), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_BEFORE), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_ABOVE), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_BELOW), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_INSERT_TABLE), visible);
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_CELL), visible);
+
+       /* Note the |= (cursor must be in a table cell). */
+       visible |= (e_editor_dom_node_get_parent_element (
+                       node, WEBKIT_TYPE_DOM_HTML_TABLE_ELEMENT) != NULL);
+       gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_TABLE), visible);
+
+       /********************** Spell Check Suggestions **********************/
+
+       /* FIXME WEBKIT No spellcheching for now
+       object = html->engine->cursor->object;
+       action_group = editor->priv->suggestion_actions;
+
+       // Remove the old content from the context menu.
+       merge_id = editor->priv->spell_suggestions_merge_id;
+       if (merge_id > 0) {
+               gtk_ui_manager_remove_ui (manager, merge_id);
+               editor->priv->spell_suggestions_merge_id = 0;
+       }
+
+       // Clear the action group for spelling suggestions.
+       list = gtk_action_group_list_actions (action_group);
+       while (list != NULL) {
+               GtkAction *action = list->data;
+
+               gtk_action_group_remove_action (action_group, action);
+               list = g_list_delete_link (list, list);
+       }
+
+       // Decide if we should show spell checking items.
+       visible =
+               !html_engine_is_selection_active (html->engine) &&
+               object != NULL && html_object_is_text (object) &&
+               !html_engine_spell_word_is_valid (html->engine);
+       action_group = editor->priv->spell_check_actions;
+       gtk_action_group_set_visible (action_group, visible);
+
+       // Exit early if spell checking items are invisible.
+       if (!visible)
+               return;
+
+       list = editor->priv->active_spell_checkers;
+       merge_id = gtk_ui_manager_new_merge_id (manager);
+       editor->priv->spell_suggestions_merge_id = merge_id;
+
+       // Handle a single active language as a special case.
+       if (g_list_length (list) == 1) {
+               editor_inline_spelling_suggestions (editor, list->data);
+               return;
+       }
+
+       // Add actions and context menu content for active languages
+       g_list_foreach (list, (GFunc) editor_spell_checkers_foreach, editor);
+       */
+}
+
+static gboolean
+editor_show_popup (EEditor *editor,
+                  GdkEventButton *event,
+                  gpointer user_data)
+{
+       GtkWidget *menu;
+
+       menu = e_editor_get_managed_widget (editor, "/context-menu");
+
+       g_signal_emit(editor, signals[UPDATE_ACTIONS], 0, event);
+
+       if (event != NULL)
+               gtk_menu_popup (
+                       GTK_MENU (menu), NULL, NULL, NULL,
+                       user_data, event->button, event->time);
+       else
+               gtk_menu_popup (
+                       GTK_MENU (menu), NULL, NULL, NULL,
+                       user_data, 0, gtk_get_current_event_time ());
+
+       return TRUE;
+}
+
 static gchar *
 editor_find_ui_file (const gchar *basename)
 {
@@ -145,6 +297,8 @@ editor_constructed (GObject *object)
        widget = GTK_WIDGET (e_editor_get_editor_widget (editor));
        gtk_container_add (GTK_CONTAINER (priv->scrolled_window), widget);
        gtk_widget_show (widget);
+       g_signal_connect_swapped (widget, "popup-event",
+               G_CALLBACK (editor_show_popup), editor);
 
        /* Add some combo boxes to the "edit" toolbar. */
 
@@ -333,6 +487,8 @@ e_editor_class_init (EEditorClass *klass)
        object_class->constructed = editor_constructed;
        object_class->dispose = editor_dispose;
 
+       klass->update_actions = editor_update_actions;
+
        g_object_class_install_property (
                object_class,
                PROP_FILENAME,
@@ -342,6 +498,16 @@ e_editor_class_init (EEditorClass *klass)
                        NULL,
                        NULL,
                        G_PARAM_READWRITE));
+
+       signals[UPDATE_ACTIONS] = g_signal_new (
+               "update-actions",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EEditorClass, update_actions),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__BOXED,
+               G_TYPE_NONE, 1,
+               GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 }
 
 static void
diff --git a/e-util/e-editor.h b/e-util/e-editor.h
index 9b878eb..b39e6a1 100644
--- a/e-util/e-editor.h
+++ b/e-util/e-editor.h
@@ -58,6 +58,9 @@ struct _EEditor {
 
 struct _EEditorClass {
        GtkBoxClass parent_class;
+
+       void            (*update_actions)       (EEditor *editor,
+                                                GdkEventButton *event);
 };
 
 GType          e_editor_get_type               (void);


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