[evolution] I#1097 - iTip formatter: Show HTML Description, when available



commit 97cd22d4a832144f9e336f959186ad8a4ff96d9b
Author: Milan Crha <mcrha redhat com>
Date:   Thu Sep 17 12:07:20 2020 +0200

    I#1097 - iTip formatter: Show HTML Description, when available
    
    Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1097

 src/calendar/gui/e-comp-editor-property-parts.c | 106 +++++++++++++++++++++---
 src/modules/itip-formatter/itip-view.c          |  79 +++++++++++++-----
 2 files changed, 151 insertions(+), 34 deletions(-)
---
diff --git a/src/calendar/gui/e-comp-editor-property-parts.c b/src/calendar/gui/e-comp-editor-property-parts.c
index b27c6b3278..bafb011d4d 100644
--- a/src/calendar/gui/e-comp-editor-property-parts.c
+++ b/src/calendar/gui/e-comp-editor-property-parts.c
@@ -541,6 +541,7 @@ struct _ECompEditorPropertyPartDescription {
 
        gboolean has_html;
        gboolean mode_html;
+       gchar *alt_desc; /* X-ALT-DESC with text/html format */
        GtkWidget *real_edit_widget;
        GtkWidget *view_as_label;
        GtkWidget *web_view_scrolled_window;
@@ -579,22 +580,26 @@ ecepp_description_update_view_mode (ECompEditorPropertyPartDescription *descript
                gtk_widget_show (description_part->view_as_label);
 
                if (description_part->mode_html) {
-                       GtkTextBuffer *buffer;
-                       GtkTextIter text_iter_start, text_iter_end;
-                       GtkWidget *edit_widget;
-                       gchar *value;
+                       if (description_part->alt_desc) {
+                               e_web_view_load_string (E_WEB_VIEW (description_part->web_view), 
description_part->alt_desc);
+                       } else {
+                               GtkTextBuffer *buffer;
+                               GtkTextIter text_iter_start, text_iter_end;
+                               GtkWidget *edit_widget;
+                               gchar *value;
 
-                       edit_widget = e_comp_editor_property_part_string_get_real_edit_widget 
(E_COMP_EDITOR_PROPERTY_PART_STRING (description_part));
-                       g_return_if_fail (GTK_IS_TEXT_VIEW (edit_widget));
+                               edit_widget = e_comp_editor_property_part_string_get_real_edit_widget 
(E_COMP_EDITOR_PROPERTY_PART_STRING (description_part));
+                               g_return_if_fail (GTK_IS_TEXT_VIEW (edit_widget));
 
-                       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
-                       gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
-                       gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
-                       value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
+                               buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (edit_widget));
+                               gtk_text_buffer_get_start_iter (buffer, &text_iter_start);
+                               gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
+                               value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, 
FALSE);
 
-                       e_web_view_load_string (E_WEB_VIEW (description_part->web_view), value ? value : "");
+                               e_web_view_load_string (E_WEB_VIEW (description_part->web_view), value ? 
value : "");
 
-                       g_free (value);
+                               g_free (value);
+                       }
 
                        gtk_widget_hide (description_part->real_edit_widget);
                        gtk_widget_show (description_part->web_view_scrolled_window);
@@ -754,7 +759,9 @@ ecepp_description_contains_html (const gchar *value)
        if (!value || !*value)
                return FALSE;
 
-       return camel_strstrcase (value, "<br>") ||
+       return camel_strstrcase (value, "<html>") ||
+               camel_strstrcase (value, "<body>") ||
+               camel_strstrcase (value, "<br>") ||
                camel_strstrcase (value, "<span>") ||
                camel_strstrcase (value, "<b>") ||
                camel_strstrcase (value, "<i>") ||
@@ -797,13 +804,81 @@ ecepp_description_fill_widget (ECompEditorPropertyPart *property_part,
        gtk_text_buffer_get_end_iter (buffer, &text_iter_end);
        value = gtk_text_buffer_get_text (buffer, &text_iter_start, &text_iter_end, FALSE);
 
+       g_clear_pointer (&description_part->alt_desc, g_free);
+
        description_part->has_html = ecepp_description_contains_html (value);
 
+       if (!description_part->has_html && value && *value) {
+               ICalProperty *prop;
+
+               for (prop = i_cal_component_get_first_property (component, I_CAL_X_PROPERTY);
+                    prop;
+                    g_object_unref (prop), prop = i_cal_component_get_next_property (component, 
I_CAL_X_PROPERTY)) {
+                       if (i_cal_property_get_x_name (prop) && g_ascii_strcasecmp (i_cal_property_get_x_name 
(prop), "X-ALT-DESC") == 0) {
+                               ICalParameter *param;
+
+                               param = i_cal_property_get_first_parameter (prop, I_CAL_FMTTYPE_PARAMETER);
+
+                               if (param && i_cal_parameter_get_fmttype (param) &&
+                                   g_ascii_strcasecmp (i_cal_parameter_get_fmttype (param), "text/html") == 
0) {
+                                       ICalValue *value;
+                                       const gchar *str = NULL;
+
+                                       value = i_cal_property_get_value (prop);
+
+                                       if (value)
+                                               str = i_cal_value_get_x (value);
+
+                                       if (str && *str) {
+                                               description_part->alt_desc = g_strdup (str);
+                                       }
+
+                                       g_clear_object (&value);
+                               }
+
+                               g_clear_object (&param);
+
+                               if (description_part->alt_desc) {
+                                       description_part->has_html = TRUE;
+                                       g_object_unref (prop);
+                                       break;
+                               }
+                       }
+               }
+       }
+
        ecepp_description_update_view_mode (description_part);
 
        g_free (value);
 }
 
+static void
+ecepp_description_fill_component (ECompEditorPropertyPart *property_part,
+                                 ICalComponent *component)
+{
+       ECompEditorPropertyPartClass *part_class;
+
+       part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (e_comp_editor_property_part_description_parent_class);
+       g_return_if_fail (part_class != NULL);
+       g_return_if_fail (part_class->fill_component != NULL);
+
+       part_class->fill_component (property_part, component);
+
+       while (e_cal_util_component_remove_x_property (component, "X-ALT-DESC")) {
+               /* Remove all of them, not only text/html, they are obsolete now */
+       }
+}
+
+static void
+ecepp_description_dispose (GObject *object)
+{
+       ECompEditorPropertyPartDescription *description_part = E_COMP_EDITOR_PROPERTY_PART_DESCRIPTION 
(object);
+
+       g_clear_pointer (&description_part->alt_desc, g_free);
+
+       G_OBJECT_CLASS (e_comp_editor_property_part_description_parent_class)->dispose (object);
+}
+
 static void
 e_comp_editor_property_part_description_init (ECompEditorPropertyPartDescription *part_description)
 {
@@ -815,6 +890,7 @@ e_comp_editor_property_part_description_class_init (ECompEditorPropertyPartDescr
 {
        ECompEditorPropertyPartStringClass *part_string_class;
        ECompEditorPropertyPartClass *part_class;
+       GObjectClass *object_class;
 
        part_string_class = E_COMP_EDITOR_PROPERTY_PART_STRING_CLASS (klass);
        part_string_class->entry_type = GTK_TYPE_TEXT_VIEW;
@@ -827,6 +903,10 @@ e_comp_editor_property_part_description_class_init (ECompEditorPropertyPartDescr
        part_class = E_COMP_EDITOR_PROPERTY_PART_CLASS (klass);
        part_class->create_widgets = ecepp_description_create_widgets;
        part_class->fill_widget = ecepp_description_fill_widget;
+       part_class->fill_component = ecepp_description_fill_component;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->dispose = ecepp_description_dispose;
 }
 
 ECompEditorPropertyPart *
diff --git a/src/modules/itip-formatter/itip-view.c b/src/modules/itip-formatter/itip-view.c
index 984a664a80..c9baa9612e 100644
--- a/src/modules/itip-formatter/itip-view.c
+++ b/src/modules/itip-formatter/itip-view.c
@@ -6336,10 +6336,12 @@ itip_view_init_view (ItipView *view)
        GString *gstring = NULL;
        GSList *list, *l;
        ICalComponent *icomp;
+       ICalProperty *prop;
        const gchar *org;
        gchar *string;
        gboolean response_enabled;
        gboolean have_alarms = FALSE;
+       gboolean description_is_html = FALSE;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
 
@@ -6576,35 +6578,72 @@ itip_view_init_view (ItipView *view)
 
        itip_view_extract_attendee_info (view);
 
-       list = e_cal_component_get_descriptions (view->priv->comp);
-       for (l = list; l; l = l->next) {
-               text = l->data;
+       icomp = e_cal_component_get_icalcomponent (view->priv->comp);
+       prop = e_cal_util_component_find_x_property (icomp, "X-ALT-DESC");
 
-               if (!text)
-                       continue;
+       if (prop) {
+               ICalParameter *param;
+
+               param = i_cal_property_get_first_parameter (prop, I_CAL_FMTTYPE_PARAMETER);
+
+               if (param && i_cal_parameter_get_fmttype (param) &&
+                   g_ascii_strcasecmp (i_cal_parameter_get_fmttype (param), "text/html") == 0) {
+                       ICalValue *value;
+                       const gchar *str = NULL;
+
+                       value = i_cal_property_get_value (prop);
+
+                       if (value)
+                               str = i_cal_value_get_x (value);
+
+                       if (str && *str) {
+                               gstring = g_string_new (str);
+                               description_is_html = TRUE;
+                       }
+
+                       g_clear_object (&value);
+               }
 
-               if (!gstring && e_cal_component_text_get_value (text))
-                       gstring = g_string_new (e_cal_component_text_get_value (text));
-               else if (e_cal_component_text_get_value (text))
-                       g_string_append_printf (gstring, "\n\n%s", e_cal_component_text_get_value (text));
+               g_clear_object (&param);
+               g_object_unref (prop);
        }
 
-       g_slist_free_full (list, e_cal_component_text_free);
+       if (!gstring) {
+               list = e_cal_component_get_descriptions (view->priv->comp);
+               for (l = list; l; l = l->next) {
+                       text = l->data;
+
+                       if (!text)
+                               continue;
+
+                       if (!gstring && e_cal_component_text_get_value (text))
+                               gstring = g_string_new (e_cal_component_text_get_value (text));
+                       else if (e_cal_component_text_get_value (text))
+                               g_string_append_printf (gstring, "\n\n%s", e_cal_component_text_get_value 
(text));
+               }
+
+               g_slist_free_full (list, e_cal_component_text_free);
+       }
 
        if (gstring) {
                gchar *html = NULL;
 
+               if (description_is_html) {
+                       /* Do nothing, trust the text provider */
+
                /* Google encodes HTML into the description, without giving a clue about it,
                   but try to guess whether it can be an HTML blob or not. */
-               if (camel_strstrcase (gstring->str, "<br>") ||
-                   camel_strstrcase (gstring->str, "<span>") ||
-                   camel_strstrcase (gstring->str, "<b>") ||
-                   camel_strstrcase (gstring->str, "<i>") ||
-                   camel_strstrcase (gstring->str, "<u>") ||
-                   camel_strstrcase (gstring->str, "&nbsp;") ||
-                   camel_strstrcase (gstring->str, "<ul>") ||
-                   camel_strstrcase (gstring->str, "<li>") ||
-                   camel_strstrcase (gstring->str, "</a>")) {
+               } else if (camel_strstrcase (gstring->str, "<html>") ||
+                          camel_strstrcase (gstring->str, "<body>") ||
+                          camel_strstrcase (gstring->str, "<br>") ||
+                          camel_strstrcase (gstring->str, "<span>") ||
+                          camel_strstrcase (gstring->str, "<b>") ||
+                          camel_strstrcase (gstring->str, "<i>") ||
+                          camel_strstrcase (gstring->str, "<u>") ||
+                          camel_strstrcase (gstring->str, "&nbsp;") ||
+                          camel_strstrcase (gstring->str, "<ul>") ||
+                          camel_strstrcase (gstring->str, "<li>") ||
+                          camel_strstrcase (gstring->str, "</a>")) {
                        gchar *ptr = gstring->str;
                        /* To make things easier, Google mixes HTML '<br>' with plain text '\n'... */
                        while (ptr = strchr (ptr, '\n'), ptr) {
@@ -6678,8 +6717,6 @@ itip_view_init_view (ItipView *view)
                g_clear_object (&from_zone);
        }
 
-       icomp = e_cal_component_get_icalcomponent (view->priv->comp);
-
         /* Set the recurrence id */
        if (check_is_instance (icomp) && datetime && e_cal_component_datetime_get_value (datetime)) {
                ECalComponentRange *recur_id;


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