[evolution/449-support-markdown-in-composer] Change how editors connect to the EHTMLEditor::content_editor



commit 4e9af47337dfa060e5233302f54b251687dc22ec
Author: Milan Crha <mcrha redhat com>
Date:   Wed Feb 9 15:14:26 2022 +0100

    Change how editors connect to the EHTMLEditor::content_editor
    
    As the content editor can change on the mode change, the connections
    to the properties and the like should change together with it.

 src/e-util/e-html-editor-actions.c | 168 ++++++++++++++++++++++---------------
 src/e-util/e-html-editor-private.h |   4 +
 src/e-util/e-html-editor.c         |  40 ++++-----
 src/e-util/e-markdown-editor.c     |   5 +-
 src/mail/e-mail-notes.c            |  56 +++++++++++--
 5 files changed, 180 insertions(+), 93 deletions(-)
---
diff --git a/src/e-util/e-html-editor-actions.c b/src/e-util/e-html-editor-actions.c
index 657340d5f7..797ad6ee44 100644
--- a/src/e-util/e-html-editor-actions.c
+++ b/src/e-util/e-html-editor-actions.c
@@ -2153,6 +2153,7 @@ e_html_editor_actions_init (EHTMLEditor *editor)
        GtkActionGroup *action_group;
        GtkUIManager *manager;
        const gchar *domain;
+       guint ii;
 
        g_return_if_fail (E_IS_HTML_EDITOR (editor));
 
@@ -2280,6 +2281,26 @@ e_html_editor_actions_init (EHTMLEditor *editor)
 
        gtk_action_set_sensitive (ACTION (UNINDENT), FALSE);
        gtk_action_set_sensitive (ACTION (FIND_AGAIN), FALSE);
+
+       g_signal_connect_object (ACTION (SUBSCRIPT), "toggled",
+               G_CALLBACK (html_editor_actions_subscript_toggled_cb), editor, 0);
+       g_signal_connect_object (ACTION (SUPERSCRIPT), "toggled",
+               G_CALLBACK (html_editor_actions_superscript_toggled_cb), editor, 0);
+       g_signal_connect (editor, "notify::mode",
+               G_CALLBACK (html_editor_actions_notify_mode_cb), NULL);
+
+       action_group = editor->priv->core_editor_actions;
+       action = gtk_action_group_get_action (action_group, "mode-html");
+       e_binding_bind_property (
+               editor, "mode",
+               action, "current-value",
+               G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+       for (ii = 0; ii < G_N_ELEMENTS (core_mode_entries); ii++) {
+               action = gtk_action_group_get_action (action_group, core_mode_entries[ii].name);
+
+               gtk_action_set_visible (action, e_html_editor_has_editor_for_mode (editor, 
core_mode_entries[ii].value));
+       }
 }
 
 static gboolean
@@ -2359,138 +2380,149 @@ e_html_editor_util_new_mode_combobox (void)
 void
 e_html_editor_actions_bind (EHTMLEditor *editor)
 {
-       GtkAction *action;
-       GtkActionGroup *action_group;
        EContentEditor *cnt_editor;
-       guint ii;
 
        g_return_if_fail (E_IS_HTML_EDITOR (editor));
 
        cnt_editor = e_html_editor_get_content_editor (editor);
 
-       action_group = editor->priv->core_editor_actions;
-       action = gtk_action_group_get_action (action_group, "mode-html");
-       e_binding_bind_property (
-               editor, "mode",
-               action, "current-value",
-               G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+       /* 'rb' for 'remember binding' */
+       #define rb(x) editor->priv->content_editor_bindings = g_slist_prepend 
(editor->priv->content_editor_bindings, g_object_ref (x))
 
-       for (ii = 0; ii < G_N_ELEMENTS (core_mode_entries); ii++) {
-               action = gtk_action_group_get_action (action_group, core_mode_entries[ii].name);
-
-               gtk_action_set_visible (action, e_html_editor_has_editor_for_mode (editor, 
core_mode_entries[ii].value));
-       }
-
-       e_action_combo_box_update_model (E_ACTION_COMBO_BOX (editor->priv->mode_combo_box));
-
-       /* Synchronize widget mode with the buttons */
-       e_html_editor_set_mode (editor, E_CONTENT_EDITOR_MODE_HTML);
+       rb (e_binding_bind_property (
+               editor->priv->fg_color_combo_box, "current-color",
+               cnt_editor, "font-color",
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
+               cnt_editor, "editable",
+               editor->priv->fg_color_combo_box, "sensitive",
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
+               editor->priv->bg_color_combo_box, "current-color",
+               cnt_editor, "background-color",
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
+               cnt_editor, "editable",
+               editor->priv->bg_color_combo_box, "sensitive",
+               G_BINDING_SYNC_CREATE));
 
-       e_binding_bind_property (
+       rb (e_binding_bind_property (
                cnt_editor, "can-redo",
                ACTION (REDO), "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "can-undo",
                ACTION (UNDO), "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "can-copy",
                ACTION (COPY), "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "can-cut",
                ACTION (CUT), "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "can-paste",
                ACTION (PASTE), "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "can-paste",
                ACTION (PASTE_QUOTE), "sensitive",
-               G_BINDING_SYNC_CREATE);
+               G_BINDING_SYNC_CREATE));
 
        /* This is connected to JUSTIFY_LEFT action only, but
         * it automatically applies on all actions in the group. */
-       e_binding_bind_property (
+       rb (e_binding_bind_property (
                cnt_editor, "alignment",
                ACTION (JUSTIFY_LEFT), "current-value",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
                cnt_editor, "bold",
                ACTION (BOLD), "active",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
                cnt_editor, "font-size",
                ACTION (FONT_SIZE_GROUP), "current-value",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
                cnt_editor, "block-format",
                ACTION (STYLE_NORMAL), "current-value",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property_full (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property_full (
                cnt_editor, "indent-level",
                ACTION (INDENT), "sensitive",
                G_BINDING_SYNC_CREATE,
                e_html_editor_indent_level_to_bool_indent_cb,
-               NULL, NULL, NULL);
-       e_binding_bind_property_full (
+               NULL, NULL, NULL));
+       rb (e_binding_bind_property_full (
                cnt_editor, "indent-level",
                ACTION (UNINDENT), "sensitive",
                G_BINDING_SYNC_CREATE,
                e_html_editor_indent_level_to_bool_unindent_cb,
-               NULL, NULL, NULL);
-       e_binding_bind_property (
+               NULL, NULL, NULL));
+       rb (e_binding_bind_property (
                cnt_editor, "italic",
                ACTION (ITALIC), "active",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
                cnt_editor, "strikethrough",
                ACTION (STRIKETHROUGH), "active",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property (
                cnt_editor, "underline",
                ACTION (UNDERLINE), "active",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property_full (
+               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
+       rb (e_binding_bind_property_full (
                cnt_editor, "font-name",
                editor->priv->font_name_combo_box, "active-id",
                G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
                e_html_editor_content_editor_font_name_to_combo_box,
                NULL,
-               NULL, NULL);
+               NULL, NULL));
 
        /* Cannot use binding, due to subscript and superscript being mutually exclusive */
-       g_signal_connect_object (ACTION (SUBSCRIPT), "toggled",
-               G_CALLBACK (html_editor_actions_subscript_toggled_cb), editor, 0);
-       g_signal_connect_object (cnt_editor, "notify::subscript",
+       editor->priv->subscript_notify_id = g_signal_connect_object (cnt_editor, "notify::subscript",
                G_CALLBACK (html_editor_actions_notify_subscript_cb), editor, 0);
-       g_signal_connect_object (ACTION (SUPERSCRIPT), "toggled",
-               G_CALLBACK (html_editor_actions_superscript_toggled_cb), editor, 0);
-       g_signal_connect_object (cnt_editor, "notify::superscript",
+       editor->priv->superscript_notify_id = g_signal_connect_object (cnt_editor, "notify::superscript",
                G_CALLBACK (html_editor_actions_notify_superscript_cb), editor, 0);
 
-       g_signal_connect (editor, "notify::mode",
-               G_CALLBACK (html_editor_actions_notify_mode_cb), NULL);
-
        /* Disable all actions and toolbars when editor is not editable */
-       e_binding_bind_property (
+       rb (e_binding_bind_property (
                cnt_editor, "editable",
                editor->priv->core_editor_actions, "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "editable",
                editor->priv->html_actions, "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "editable",
                editor->priv->spell_check_actions, "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
+               G_BINDING_SYNC_CREATE));
+       rb (e_binding_bind_property (
                cnt_editor, "editable",
                editor->priv->suggestion_actions, "sensitive",
-               G_BINDING_SYNC_CREATE);
+               G_BINDING_SYNC_CREATE));
+
+       #undef rb
+}
+
+void
+e_html_editor_actions_unbind (EHTMLEditor *editor)
+{
+       EContentEditor *cnt_editor;
+
+       g_slist_foreach (editor->priv->content_editor_bindings, (GFunc) g_binding_unbind, NULL);
+       g_slist_free_full (editor->priv->content_editor_bindings, g_object_unref);
+       editor->priv->content_editor_bindings = NULL;
+
+       cnt_editor = e_html_editor_get_content_editor (editor);
+
+       if (cnt_editor) {
+               e_signal_disconnect_notify_handler (cnt_editor, &editor->priv->subscript_notify_id);
+               e_signal_disconnect_notify_handler (cnt_editor, &editor->priv->superscript_notify_id);
+       }
 }
 
 void
diff --git a/src/e-util/e-html-editor-private.h b/src/e-util/e-html-editor-private.h
index 45f44e69bd..909a603011 100644
--- a/src/e-util/e-html-editor-private.h
+++ b/src/e-util/e-html-editor-private.h
@@ -101,6 +101,9 @@ struct _EHTMLEditorPrivate {
        GCancellable *mode_change_content_cancellable;
 
        gchar *filename;
+       GSList *content_editor_bindings; /* reffed GBinding-s related to the EContentEditor */
+       gulong subscript_notify_id;
+       gulong superscript_notify_id;
 
        guint spell_suggestions_merge_id;
        guint recent_spell_languages_merge_id;
@@ -112,6 +115,7 @@ struct _EHTMLEditorPrivate {
 
 void           e_html_editor_actions_init      (EHTMLEditor *editor);
 void           e_html_editor_actions_bind      (EHTMLEditor *editor);
+void           e_html_editor_actions_unbind    (EHTMLEditor *editor);
 void           e_html_editor_actions_update_spellcheck_languages_menu
                                                (EHTMLEditor *editor,
                                                 const gchar * const *languages);
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 019a66ee5b..07767f54e9 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -1074,6 +1074,12 @@ html_editor_dispose (GObject *object)
 
        g_clear_object (&priv->mode_change_content_cancellable);
 
+       /* Do not unbind/disconnect signal handlers here, just free/unset them */
+       g_slist_free_full (priv->content_editor_bindings, g_object_unref);
+       priv->content_editor_bindings = NULL;
+       priv->subscript_notify_id = 0;
+       priv->superscript_notify_id = 0;
+
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_html_editor_parent_class)->dispose (object);
 }
@@ -1196,6 +1202,7 @@ e_html_editor_init (EHTMLEditor *editor)
 
        priv = editor->priv;
 
+       priv->mode = E_CONTENT_EDITOR_MODE_HTML;
        priv->manager = gtk_ui_manager_new ();
        priv->core_actions = gtk_action_group_new ("core");
        priv->core_editor_actions = gtk_action_group_new ("core-editor");
@@ -1230,23 +1237,8 @@ e_html_editor_content_editor_initialized (EContentEditor *content_editor,
        g_return_if_fail (E_IS_HTML_EDITOR (html_editor));
        g_return_if_fail (content_editor == e_html_editor_get_content_editor (html_editor));
 
-       e_binding_bind_property (
-               html_editor->priv->fg_color_combo_box, "current-color",
-               content_editor, "font-color",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
-               content_editor, "editable",
-               html_editor->priv->fg_color_combo_box, "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_binding_bind_property (
-               html_editor->priv->bg_color_combo_box, "current-color",
-               content_editor, "background-color",
-               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-       e_binding_bind_property (
-               content_editor, "editable",
-               html_editor->priv->bg_color_combo_box, "sensitive",
-               G_BINDING_SYNC_CREATE);
-       e_html_editor_actions_bind (html_editor);
+       /* Synchronize widget mode with the buttons */
+       e_html_editor_set_mode (html_editor, E_CONTENT_EDITOR_MODE_HTML);
 
        g_object_set (G_OBJECT (content_editor),
                "halign", GTK_ALIGN_FILL,
@@ -1689,6 +1681,8 @@ e_html_editor_update_content_on_mode_change_cb (GObject *source_object,
                        }
                }
 
+               e_content_editor_clear_undo_redo_history (editor->priv->use_content_editor);
+
                e_content_editor_util_free_content_hash (content_hash);
        }
 
@@ -1731,7 +1725,8 @@ e_html_editor_set_mode (EHTMLEditor *editor,
        if (mode == E_CONTENT_EDITOR_MODE_UNKNOWN)
                mode = E_CONTENT_EDITOR_MODE_PLAIN_TEXT;
 
-       if (editor->priv->mode == mode)
+       /* In case the same mode is set, but no editor is assigned, then assign it */
+       if (editor->priv->mode == mode && editor->priv->use_content_editor != NULL)
                return;
 
        if (editor->priv->mode_change_content_cancellable) {
@@ -1742,11 +1737,15 @@ e_html_editor_set_mode (EHTMLEditor *editor,
        cnt_editor = e_html_editor_get_content_editor_for_mode (editor, mode);
 
        if (cnt_editor) {
-               if (cnt_editor != editor->priv->use_content_editor) {
+               gboolean editor_changed = cnt_editor != editor->priv->use_content_editor;
+
+               if (editor_changed) {
                        EContentEditorInterface *iface;
                        gboolean is_focused = FALSE;
 
                        if (editor->priv->use_content_editor) {
+                               e_html_editor_actions_unbind (editor);
+
                                is_focused = e_content_editor_is_focus (editor->priv->use_content_editor);
 
                                editor->priv->mode_change_content_cancellable = g_cancellable_new ();
@@ -1811,6 +1810,9 @@ e_html_editor_set_mode (EHTMLEditor *editor,
                editor->priv->mode = mode;
                editor->priv->use_content_editor = cnt_editor;
 
+               if (editor_changed)
+                       e_html_editor_actions_bind (editor);
+
                g_object_set (G_OBJECT (cnt_editor), "mode", mode, NULL);
                g_object_notify (G_OBJECT (editor), "mode");
        }
diff --git a/src/e-util/e-markdown-editor.c b/src/e-util/e-markdown-editor.c
index 4771e35c37..7c1f7b50f9 100644
--- a/src/e-util/e-markdown-editor.c
+++ b/src/e-util/e-markdown-editor.c
@@ -443,6 +443,9 @@ e_markdown_editor_clear_undo_redo_history (EContentEditor *cnt_editor)
        EMarkdownEditor *self = E_MARKDOWN_EDITOR (cnt_editor);
 
        e_widget_undo_reset (GTK_WIDGET (self->priv->text_view));
+
+       g_object_notify (G_OBJECT (self), "can-undo");
+       g_object_notify (G_OBJECT (self), "can-redo");
 }
 
 static void
@@ -1263,7 +1266,7 @@ e_markdown_editor_get_property (GObject *object,
                        return;
 
                case PROP_FONT_SIZE:
-                       g_value_set_int (value, 0);
+                       g_value_set_int (value, E_CONTENT_EDITOR_FONT_SIZE_NORMAL);
                        return;
 
                case PROP_INDENT_LEVEL:
diff --git a/src/mail/e-mail-notes.c b/src/mail/e-mail-notes.c
index 4bddbdd202..edca97ef6d 100644
--- a/src/mail/e-mail-notes.c
+++ b/src/mail/e-mail-notes.c
@@ -49,6 +49,7 @@ struct _EMailNotesEditor {
        EAttachmentPaned *attachment_paned; /* not referenced */
        EFocusTracker *focus_tracker;
        GtkActionGroup *action_group;
+       GBinding *attachment_paned_binding;
 
        gboolean had_message;
        CamelMimeMessage *message;
@@ -954,15 +955,58 @@ action_save_and_close_cb (GtkAction *action,
                mail_notes_get_content_ready_cb, scd);
 }
 
+static void
+notes_editor_notify_mode_cb (GObject *object,
+                            GParamSpec *param,
+                            EMailNotesEditor *notes_editor)
+{
+       g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+       if (notes_editor->attachment_paned_binding) {
+               g_binding_unbind (notes_editor->attachment_paned_binding);
+               g_clear_object (&notes_editor->attachment_paned_binding);
+       }
+
+       if (notes_editor->editor) {
+               EContentEditor *cnt_editor;
+
+               cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
+
+               if (cnt_editor) {
+                       EActivityBar *activity_bar;
+                       gboolean can_edit;
+
+                       activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+                       can_edit = notes_editor->had_message && !e_activity_bar_get_activity (activity_bar);
+
+                       g_object_set (cnt_editor, "editable", can_edit, NULL);
+
+                       notes_editor->attachment_paned_binding = g_object_ref (e_binding_bind_property (
+                               cnt_editor, "editable",
+                               notes_editor->attachment_paned, "sensitive",
+                               G_BINDING_SYNC_CREATE));
+               }
+       }
+}
+
 static void
 e_mail_notes_editor_dispose (GObject *object)
 {
        EMailNotesEditor *notes_editor = E_MAIL_NOTES_EDITOR (object);
 
-       notes_editor->editor = NULL;
+       if (notes_editor->editor) {
+               EActivityBar *activity_bar;
+
+               activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+               g_signal_handlers_disconnect_by_func (activity_bar,
+                       G_CALLBACK (notes_editor_update_editable_on_notify_cb), notes_editor);
+
+               notes_editor->editor = NULL;
+       }
 
        g_clear_object (&notes_editor->focus_tracker);
        g_clear_object (&notes_editor->action_group);
+       g_clear_object (&notes_editor->attachment_paned_binding);
 
        /* Chain up to parent's method */
        G_OBJECT_CLASS (e_mail_notes_editor_parent_class)->dispose (object);
@@ -1143,10 +1187,10 @@ e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
        notes_editor->attachment_paned = E_ATTACHMENT_PANED (widget);
        gtk_widget_show (widget);
 
-       e_binding_bind_property (
+       notes_editor->attachment_paned_binding = g_object_ref (e_binding_bind_property (
                cnt_editor, "editable",
                widget, "sensitive",
-               G_BINDING_SYNC_CREATE);
+               G_BINDING_SYNC_CREATE));
 
        /* Configure an EFocusTracker to manage selection actions. */
        focus_tracker = e_focus_tracker_new (GTK_WINDOW (notes_editor));
@@ -1171,8 +1215,10 @@ e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
 
        activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
 
-       g_signal_connect_object (activity_bar, "notify::activity",
-               G_CALLBACK (notes_editor_update_editable_on_notify_cb), notes_editor, 0);
+       g_signal_connect (activity_bar, "notify::activity",
+               G_CALLBACK (notes_editor_update_editable_on_notify_cb), notes_editor);
+       g_signal_connect_object (notes_editor->editor, "notify::mode",
+               G_CALLBACK (notes_editor_notify_mode_cb), notes_editor, 0);
 
        notes_editor->folder = g_object_ref (folder);
        notes_editor->uid = g_strdup (uid);


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