X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-gtkhtml-msg-view.c;h=6bd1abdb41ce0463e135bb441972716b685f760f;hb=a5f1624b5d7a4e153fd1e324f993917ec4492122;hp=45321191250871f7437a90a029a848efddeba09c;hpb=a27cf1796b900bc0fbf80dfdc504d8346bd59cf3;p=modest diff --git a/src/widgets/modest-gtkhtml-msg-view.c b/src/widgets/modest-gtkhtml-msg-view.c index 4532119..6bd1abd 100644 --- a/src/widgets/modest-gtkhtml-msg-view.c +++ b/src/widgets/modest-gtkhtml-msg-view.c @@ -36,25 +36,34 @@ #include #include #include +#include #include #include #include -#include +#ifdef MODEST_TOOLKIT_HILDON2 +#include +#include +#else +#include +#endif #include #include #include #include #include +#include +#include /* FIXNE: we should have no maemo-deps in widgets/ */ -#ifdef MODEST_PLATFORM_MAEMO +#ifndef MODEST_TOOLKIT_GTK #include "maemo/modest-hildon-includes.h" -#endif /*MODEST_PLATFORM_MAEMO*/ +#endif /*!MODEST_TOOLKIT_GTK*/ /* 'private'/'protected' functions */ static void modest_gtkhtml_msg_view_class_init (ModestGtkhtmlMsgViewClass *klass); +static void tny_header_view_init (gpointer g, gpointer iface_data); static void tny_msg_view_init (gpointer g, gpointer iface_data); static void tny_mime_part_view_init (gpointer g, gpointer iface_data); static void modest_mime_part_view_init (gpointer g, gpointer iface_data); @@ -69,6 +78,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GPa /* headers signals */ static void on_recpt_activated (ModestMailHeaderView *header_view, const gchar *address, ModestGtkhtmlMsgView *msg_view); +static void on_show_details (ModestMailHeaderView *header_view, ModestGtkhtmlMsgView *msg_view); static void on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer userdata); /* body view signals */ @@ -76,9 +86,11 @@ static gboolean on_activate_link (GtkWidget *widget, const gchar *uri, ModestGtk static gboolean on_fetch_url (GtkWidget *widget, const gchar *uri, TnyStream *stream, ModestGtkhtmlMsgView *msg_view); static gboolean on_link_hover (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *msg_view); +static void on_limit_error (GtkWidget *widget, ModestGtkhtmlMsgView *msg_view); #ifdef MAEMO_CHANGES static void on_tap_and_hold (GtkWidget *widget, gpointer userdata); +static gboolean on_tap_and_hold_query (GtkWidget *widget, GdkEvent *event, gpointer userdata); #endif /*MAEMO_CHANGES*/ @@ -105,6 +117,15 @@ static gboolean motion_notify_event (GtkWidget *widget, gpointer userdata); #endif +static gboolean +button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer userdata); +static gboolean +button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer userdata); + /* GtkContainer methods */ static void forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer userdata); @@ -119,6 +140,11 @@ static TnyMimePart* modest_msg_view_mp_get_part_default (TnyMimePartView *self); /* ModestMimePartView implementation */ static gboolean modest_msg_view_mp_is_empty (ModestMimePartView *self); static gboolean modest_msg_view_mp_is_empty_default (ModestMimePartView *self); +/* TnyHeaderView implementation */ +static void modest_msg_view_set_header (TnyHeaderView *self, TnyHeader *header); +static void modest_msg_view_set_header_default (TnyHeaderView *self, TnyHeader *header); +static void modest_msg_view_clear_header (TnyHeaderView *self); +static void modest_msg_view_clear_header_default (TnyHeaderView *self); /* TnyMsgView implementation */ static TnyMsg *modest_msg_view_get_msg (TnyMsgView *self); static TnyMsg *modest_msg_view_get_msg_default (TnyMsgView *self); @@ -147,6 +173,7 @@ static gboolean modest_msg_view_search_default (ModestISearchView *self, const g static gboolean modest_msg_view_search_next (ModestISearchView *self); static gboolean modest_msg_view_search_next_default (ModestISearchView *self); /* ModestMsgView implementation */ +static void modest_gtkhtml_msg_view_set_msg_with_other_body (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body); static GtkAdjustment *modest_gtkhtml_msg_view_get_vadjustment (ModestMsgView *self); static GtkAdjustment *modest_gtkhtml_msg_view_get_hadjustment (ModestMsgView *self); static void modest_gtkhtml_msg_view_set_vadjustment (ModestMsgView *self, GtkAdjustment *vadj); @@ -159,6 +186,10 @@ static TnyList *modest_gtkhtml_msg_view_get_selected_attachments (ModestMsgView static TnyList *modest_gtkhtml_msg_view_get_attachments (ModestMsgView *self); static void modest_gtkhtml_msg_view_grab_focus (ModestMsgView *self); static void modest_gtkhtml_msg_view_remove_attachment (ModestMsgView *view, TnyMimePart *attachment); +static void modest_gtkhtml_msg_view_request_fetch_images (ModestMsgView *view); +static void modest_gtkhtml_msg_view_set_branding (ModestMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon); +static gboolean modest_gtkhtml_msg_view_has_blocked_external_images (ModestMsgView *view); +static void modest_gtkhtml_msg_view_set_msg_with_other_body_default (ModestMsgView *view, TnyMsg *msg, TnyMimePart *part); static GtkAdjustment *modest_gtkhtml_msg_view_get_vadjustment_default (ModestMsgView *self); static GtkAdjustment *modest_gtkhtml_msg_view_get_hadjustment_default (ModestMsgView *self); static void modest_gtkhtml_msg_view_set_vadjustment_default (ModestMsgView *self, GtkAdjustment *vadj); @@ -171,10 +202,14 @@ static TnyList *modest_gtkhtml_msg_view_get_selected_attachments_default (Modest static TnyList *modest_gtkhtml_msg_view_get_attachments_default (ModestMsgView *self); static void modest_gtkhtml_msg_view_grab_focus_default (ModestMsgView *self); static void modest_gtkhtml_msg_view_remove_attachment_default (ModestMsgView *view, TnyMimePart *attachment); +static gboolean modest_gtkhtml_msg_view_has_blocked_external_images_default (ModestMsgView *view); +static void modest_gtkhtml_msg_view_request_fetch_images_default (ModestMsgView *view); +static void modest_gtkhtml_msg_view_set_branding_default (ModestMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon); /* internal api */ +static void set_header (ModestGtkhtmlMsgView *self, TnyHeader *header); static TnyMsg *get_message (ModestGtkhtmlMsgView *self); -static void set_message (ModestGtkhtmlMsgView *self, TnyMsg *tny_msg); +static void set_message (ModestGtkhtmlMsgView *self, TnyMsg *tny_msg, TnyMimePart *other_body); static gboolean is_empty (ModestGtkhtmlMsgView *self); static void set_zoom (ModestGtkhtmlMsgView *self, gdouble zoom); static gdouble get_zoom (ModestGtkhtmlMsgView *self); @@ -192,6 +227,9 @@ static TnyList *get_selected_attachments (ModestGtkhtmlMsgView *self); static TnyList *get_attachments (ModestGtkhtmlMsgView *self); static void grab_focus (ModestGtkhtmlMsgView *self); static void remove_attachment (ModestGtkhtmlMsgView *view, TnyMimePart *attachment); +static void request_fetch_images (ModestGtkhtmlMsgView *view); +static void set_branding (ModestGtkhtmlMsgView *view, const gchar *brand_name, const GdkPixbuf *brand_icon); +static gboolean has_blocked_external_images (ModestGtkhtmlMsgView *view); /* list properties */ enum { @@ -214,6 +252,11 @@ struct _ModestGtkhtmlMsgViewPrivate { GtkWidget *html_scroll; GtkWidget *attachments_box; +#ifdef MODEST_TOOLKIT_HILDON2 + GtkWidget *priority_box; + GtkWidget *priority_icon; +#endif + /* internal adjustments for set_scroll_adjustments */ GtkAdjustment *hadj; GtkAdjustment *vadj; @@ -224,6 +267,14 @@ struct _ModestGtkhtmlMsgViewPrivate { GdkWindow *headers_window; GdkWindow *html_window; + /* id handler for dragged scroll */ + guint idle_motion_id; + + /* idle changes count */ + gint idle_changes_count; + guint idle_readjust_scroll_id; + guint idle_resize_children_id; + /* zoom */ gdouble current_zoom; @@ -269,6 +320,13 @@ modest_gtkhtml_msg_view_get_type (void) NULL /* interface_data */ }; + static const GInterfaceInfo tny_header_view_info = + { + (GInterfaceInitFunc) tny_header_view_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + static const GInterfaceInfo modest_mime_part_view_info = { (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */ @@ -301,6 +359,9 @@ modest_gtkhtml_msg_view_get_type (void) "ModestGtkhtmlMsgView", &my_info, 0); + g_type_add_interface_static (my_type, TNY_TYPE_HEADER_VIEW, + &tny_header_view_info); + g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, &tny_mime_part_view_info); @@ -349,6 +410,8 @@ modest_gtkhtml_msg_view_class_init (ModestGtkhtmlMsgViewClass *klass) container_class->forall = forall; container_class->remove = container_remove; + klass->set_header_func = modest_msg_view_set_header_default; + klass->clear_header_func = modest_msg_view_clear_header_default; klass->set_scroll_adjustments = set_scroll_adjustments; klass->get_part_func = modest_msg_view_mp_get_part_default; klass->set_part_func = modest_msg_view_mp_set_part_default; @@ -365,6 +428,7 @@ modest_gtkhtml_msg_view_class_init (ModestGtkhtmlMsgViewClass *klass) klass->zoom_plus_func = modest_msg_view_zoom_plus_default; klass->search_func = modest_msg_view_search_default; klass->search_next_func = modest_msg_view_search_next_default; + klass->set_msg_with_other_body_func = modest_gtkhtml_msg_view_set_msg_with_other_body_default; klass->get_vadjustment_func = modest_gtkhtml_msg_view_get_vadjustment_default; klass->get_hadjustment_func = modest_gtkhtml_msg_view_get_hadjustment_default; klass->set_vadjustment_func = modest_gtkhtml_msg_view_set_vadjustment_default; @@ -377,6 +441,9 @@ modest_gtkhtml_msg_view_class_init (ModestGtkhtmlMsgViewClass *klass) klass->get_attachments_func = modest_gtkhtml_msg_view_get_attachments_default; klass->grab_focus_func = modest_gtkhtml_msg_view_grab_focus_default; klass->remove_attachment_func = modest_gtkhtml_msg_view_remove_attachment_default; + klass->request_fetch_images_func = modest_gtkhtml_msg_view_request_fetch_images_default; + klass->set_branding_func = modest_gtkhtml_msg_view_set_branding_default; + klass->has_blocked_external_images_func = modest_gtkhtml_msg_view_has_blocked_external_images_default; g_type_class_add_private (gobject_class, sizeof(ModestGtkhtmlMsgViewPrivate)); @@ -535,6 +602,8 @@ set_hadjustment_values (ModestGtkhtmlMsgView *self, { GtkAllocation view_allocation; GtkAdjustment *hadj = get_hadjustment (self); + gint full_width = 0; + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); get_view_allocation (self, &view_allocation); hadj->page_size = view_allocation.width; @@ -544,11 +613,20 @@ set_hadjustment_values (ModestGtkhtmlMsgView *self, hadj->lower = 0; hadj->upper = view_allocation.width; + /* Get the real width of the embedded html */ + if (priv->html_scroll && GTK_WIDGET_VISIBLE(priv->html_scroll)) { + GtkAdjustment *html_hadj; + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + full_width += html_hadj->upper; + } + + hadj->upper = MAX (view_allocation.width, full_width); + reclamp_adjustment (hadj, value_changed); } -static void +static void set_vadjustment_values (ModestGtkhtmlMsgView *self, gboolean *value_changed) { @@ -591,11 +669,13 @@ set_scroll_adjustments (ModestGtkhtmlMsgView *self, GtkAdjustment *hadj, GtkAdjustment *vadj) { - ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); set_hadjustment (self, hadj); set_vadjustment (self, vadj); +#ifndef MODEST_TOOLKIT_HILDON2 + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->body_view), vadj); +#endif } static void @@ -833,6 +913,12 @@ size_allocate (GtkWidget *widget, allocation->height != widget->allocation.height)) gdk_window_invalidate_rect (widget->window, NULL, FALSE); + if (priv->idle_readjust_scroll_id == 0 && priv->idle_changes_count < 5 && widget->allocation.width != allocation->width) { + g_object_ref (self); + priv->idle_readjust_scroll_id = g_idle_add ((GSourceFunc) idle_readjust_scroll, self); + priv->idle_changes_count ++; + } + widget->allocation = *allocation; set_hadjustment_values (self, &hadj_value_changed); set_vadjustment_values (self, &vadj_value_changed); @@ -948,6 +1034,18 @@ adjustment_value_changed (GtkAdjustment *adj, gpointer data) } } +static gboolean +resize_children_idle (GtkContainer *cont) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (cont); + if (GTK_WIDGET_DRAWABLE (cont)) { + gtk_container_resize_children (cont); + } + priv->idle_resize_children_id = 0; + + return FALSE; +} + static void html_adjustment_changed (GtkAdjustment *adj, gpointer userdata) @@ -973,7 +1071,8 @@ html_adjustment_changed (GtkAdjustment *adj, if (GTK_WIDGET_DRAWABLE (priv->html_scroll)) { gdk_window_resize (priv->html_window, (gint) priv->hadj->upper, (gint) new_height); gdk_window_process_updates (priv->view_window, TRUE); - gtk_container_resize_children (GTK_CONTAINER (self)); + if (priv->idle_resize_children_id == 0) + priv->idle_resize_children_id = gdk_threads_add_idle ((GSourceFunc) resize_children_idle, self); } } @@ -981,27 +1080,42 @@ html_adjustment_changed (GtkAdjustment *adj, gboolean idle_readjust_scroll (ModestGtkhtmlMsgView *self) { + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); /* We're out the main lock */ gdk_threads_enter (); if (GTK_WIDGET_DRAWABLE (self)) { - ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); GtkAdjustment *html_vadj; + GtkAdjustment *html_hadj; + html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); - html_vadj->page_size = html_vadj->upper; - gtk_adjustment_changed (html_vadj); - gtk_widget_queue_resize (GTK_WIDGET (self)); - gtk_widget_queue_draw (GTK_WIDGET (self)); + html_vadj->upper = 0; + html_vadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); + + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_hadj->upper = 0; + html_hadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_hadj), "changed"); + + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1); + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1); + + gtk_widget_queue_resize (GTK_WIDGET (priv->body_view)); + gtk_widget_queue_draw (GTK_WIDGET (priv->body_view)); /* Just another hack for making readjust really work. This forces an update * of the scroll, and then, make the scroll really update properly the * the size and not corrupt scrollable area */ gtk_adjustment_set_value (priv->vadj, 1.0); gtk_adjustment_set_value (priv->vadj, 0.0); + } + priv->idle_readjust_scroll_id = 0; g_object_unref (G_OBJECT (self)); + gdk_threads_leave (); return FALSE; @@ -1012,7 +1126,6 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) { ModestGtkhtmlMsgViewPrivate *priv; GtkAdjustment *html_vadj; - GtkWidget *separator; GTK_WIDGET_UNSET_FLAGS (obj, GTK_NO_WINDOW); gtk_widget_set_redraw_on_allocate (GTK_WIDGET (obj), TRUE); @@ -1021,6 +1134,9 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(obj); + priv->idle_changes_count = 0; + priv->idle_readjust_scroll_id = 0; + priv->idle_resize_children_id = 0; priv->current_zoom = 1.0; priv->hadj = NULL; @@ -1030,6 +1146,8 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) priv->headers_window = NULL; priv->html_window = NULL; + priv->idle_motion_id = 0; + gtk_widget_push_composite_child (); priv->html_scroll = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_composite_name (priv->html_scroll, "contents"); @@ -1039,10 +1157,20 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) priv->msg = NULL; priv->body_view = GTK_WIDGET (g_object_new (MODEST_TYPE_GTKHTML_MIME_PART_VIEW, NULL)); - priv->mail_header_view = GTK_WIDGET(modest_mail_header_view_new (TRUE)); +#ifdef MODEST_TOOLKIT_HILDON2 + priv->mail_header_view = GTK_WIDGET(modest_compact_mail_header_view_new ()); +#else + priv->mail_header_view = GTK_WIDGET(modest_expander_mail_header_view_new (TRUE)); +#endif gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); - priv->attachments_view = GTK_WIDGET(modest_attachments_view_new (NULL)); +#ifdef MODEST_TOOLKIT_HILDON2 + modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), + MODEST_ATTACHMENTS_VIEW_STYLE_LINKS); +#else + modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), + MODEST_ATTACHMENTS_VIEW_STYLE_SELECTABLE); +#endif g_signal_connect (G_OBJECT(priv->body_view), "activate_link", G_CALLBACK(on_activate_link), obj); @@ -1050,13 +1178,21 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) G_CALLBACK(on_fetch_url), obj); g_signal_connect (G_OBJECT(priv->body_view), "link_hover", G_CALLBACK(on_link_hover), obj); + g_signal_connect (G_OBJECT(priv->body_view), "limit_error", + G_CALLBACK(on_limit_error), obj); #ifdef MAEMO_CHANGES g_signal_connect (G_OBJECT(priv->body_view), "motion-notify-event", G_CALLBACK (motion_notify_event), obj); #endif + g_signal_connect (G_OBJECT (priv->body_view), "button-press-event", + G_CALLBACK (button_press_event), obj); + g_signal_connect (G_OBJECT (priv->body_view), "button-release-event", + G_CALLBACK (button_release_event), obj); g_signal_connect (G_OBJECT (priv->mail_header_view), "recpt-activated", G_CALLBACK (on_recpt_activated), obj); + g_signal_connect (G_OBJECT (priv->mail_header_view), "show-details", + G_CALLBACK (on_show_details), obj); g_signal_connect (G_OBJECT (priv->attachments_view), "activate", G_CALLBACK (on_attachment_activated), obj); @@ -1067,15 +1203,32 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) G_CALLBACK (html_adjustment_changed), obj); gtk_widget_push_composite_child (); - priv->headers_box = gtk_vbox_new (0, FALSE); + priv->headers_box = gtk_vbox_new (FALSE, MODEST_MARGIN_DEFAULT); gtk_widget_set_composite_name (priv->headers_box, "headers"); gtk_widget_pop_composite_child (); if (priv->mail_header_view) gtk_box_pack_start (GTK_BOX(priv->headers_box), priv->mail_header_view, FALSE, FALSE, 0); - + +#ifdef MODEST_TOOLKIT_HILDON2 + priv->priority_icon = gtk_image_new (); + gtk_misc_set_alignment (GTK_MISC (priv->priority_icon), 0.0, 0.5); + if (priv->priority_icon) { + priv->priority_box = (GtkWidget *) + modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), + _("mcen_me_editor_message_priority"), + priv->priority_icon, + FALSE, FALSE); + + gtk_widget_hide_all (priv->priority_box); + } +#endif if (priv->attachments_view) { +#ifndef MODEST_TOOLKIT_HILDON2 gchar *att_label = g_strconcat (_("mcen_me_viewer_attachments"), ":", NULL); +#else + gchar *att_label = g_strconcat (_("mail_va_attachment"), ":", NULL); +#endif priv->attachments_box = (GtkWidget *) modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), @@ -1086,8 +1239,10 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) g_free (att_label); } +#ifndef MODEST_TOOLKIT_HILDON2 separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX(priv->headers_box), separator, FALSE, FALSE, 0); +#endif gtk_widget_set_parent (priv->headers_box, GTK_WIDGET (obj)); @@ -1097,6 +1252,7 @@ modest_gtkhtml_msg_view_init (ModestGtkhtmlMsgView *obj) #ifdef MAEMO_CHANGES gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->body_view), NULL, NULL, 0); g_signal_connect (G_OBJECT (priv->body_view), "tap-and-hold", G_CALLBACK (on_tap_and_hold), obj); + g_signal_connect (G_OBJECT (priv->body_view), "tap-and-hold-query", G_CALLBACK (on_tap_and_hold_query), obj); #endif } @@ -1113,6 +1269,21 @@ modest_gtkhtml_msg_view_finalize (GObject *obj) g_object_unref (G_OBJECT(priv->msg)); priv->msg = NULL; } + + if (priv->idle_resize_children_id > 0) { + g_source_remove (priv->idle_resize_children_id); + priv->idle_resize_children_id = 0; + } + + if (priv->idle_readjust_scroll_id > 0) { + g_source_remove (priv->idle_readjust_scroll_id); + priv->idle_readjust_scroll_id = 0; + } + + if (priv->idle_motion_id > 0) { + g_source_remove (priv->idle_motion_id); + priv->idle_motion_id = 0; + } /* we cannot disconnect sigs, because priv->body_view is * already dead */ @@ -1161,11 +1332,63 @@ motion_notify_event (GtkWidget *widget, value = priv->vadj->upper - priv->vadj->page_size; gtk_adjustment_set_value (priv->vadj, value); - } + } return FALSE; } #endif +static gboolean +idle_motion (gpointer userdata) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata); + if (GTK_HTML (priv->body_view)->in_selection_drag) { + gdouble offset; + GtkAdjustment *adj; + gint gdk_y; + gdk_window_get_pointer (gtk_widget_get_parent_window (priv->body_view), NULL, &gdk_y, NULL); + offset= (gdouble) (priv->headers_box->requisition.height + gdk_y); + adj = GTK_ADJUSTMENT (priv->vadj); + if (offset < adj->value + adj->step_increment) { + gtk_adjustment_set_value (adj, MAX (offset + adj->page_increment - adj->page_size, 0.0)); + } else if (offset > adj->value + adj->page_increment) { + gtk_adjustment_set_value (adj, MIN (offset - adj->page_increment, adj->upper - adj->page_size)); + } + gtk_widget_queue_resize (userdata); + } + return TRUE; +} + +static gboolean +button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer userdata) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata); + + if (priv->idle_motion_id == 0) { + priv->idle_motion_id = g_timeout_add (200, idle_motion, userdata); + } + return FALSE; +} + +static gboolean +button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer userdata) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (userdata); + + if (priv->idle_motion_id > 0) { + gint gdk_y; + g_source_remove (priv->idle_motion_id); + + priv->idle_motion_id = 0;; + gdk_window_get_pointer (gtk_widget_get_parent_window (priv->body_view), NULL, &gdk_y, NULL); + event->y = (gdouble) gdk_y; + } + return FALSE; +} + static GtkAdjustment * get_vadjustment (ModestGtkhtmlMsgView *self) { @@ -1301,6 +1524,18 @@ on_tap_and_hold (GtkWidget *widget, g_signal_emit_by_name (G_OBJECT (self), "link-contextual", priv->last_url); } + +static gboolean +on_tap_and_hold_query (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + ModestGtkhtmlMsgView *self = (ModestGtkhtmlMsgView *) data; + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); + + /* Don't show the tap and hold animation if no url below */ + return (priv->last_url == NULL); +} #endif static void @@ -1312,18 +1547,60 @@ on_recpt_activated (ModestMailHeaderView *header_view, } static void +on_show_details (ModestMailHeaderView *header_view, + ModestGtkhtmlMsgView *self) +{ + g_signal_emit_by_name (G_OBJECT (self), "show-details"); +} + +static void on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer self) { g_signal_emit_by_name (G_OBJECT(self), "attachment_clicked", mime_part); } +static void +request_fetch_images (ModestGtkhtmlMsgView *self) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); + TnyMimePart *part; + + /* The message could have not been downloaded yet */ + if (priv->msg) { + modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), TRUE); + part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (priv->body_view)); + if (part) { + tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), part); + g_object_unref (part); + } + tny_msg_set_allow_external_images (TNY_MSG (priv->msg), TRUE); + } +} + +static void +set_branding (ModestGtkhtmlMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); + + modest_mail_header_view_set_branding (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), brand_name, brand_icon); +} + +static gboolean +has_blocked_external_images (ModestGtkhtmlMsgView *self) +{ + ModestGtkhtmlMsgViewPrivate *priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); + + return (modest_mime_part_view_has_external_images (MODEST_MIME_PART_VIEW (priv->body_view)) && + !modest_mime_part_view_get_view_images (MODEST_MIME_PART_VIEW (priv->body_view))); +} + static gboolean on_activate_link (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *self) { gboolean result; g_return_val_if_fail (self, FALSE); - + g_signal_emit_by_name (G_OBJECT(self), "activate-link", uri, &result); return result; @@ -1344,6 +1621,11 @@ on_link_hover (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMsgView *self) return result; } +static void +on_limit_error (GtkWidget *widget, ModestGtkhtmlMsgView *msg_view) +{ + g_signal_emit_by_name (G_OBJECT (msg_view), "limit-error"); +} static TnyMimePart * @@ -1426,6 +1708,8 @@ on_fetch_url (GtkWidget *widget, const gchar *uri, const gchar* my_uri; TnyMimePart *part = NULL; + + priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); /* @@ -1440,34 +1724,43 @@ on_fetch_url (GtkWidget *widget, const gchar *uri, /* now try to find the embedded image */ part = find_cid_image (priv->msg, my_uri); + if (!part) { - g_printerr ("modest: %s: '%s' not found\n", __FUNCTION__, my_uri); - return FALSE; + if (g_str_has_prefix (uri, "http:")) { + if (modest_mime_part_view_get_view_images (MODEST_MIME_PART_VIEW (priv->body_view))) { + gboolean result = FALSE; + g_signal_emit_by_name (self, "fetch-image", uri, stream, &result); + return result; + } else { + /* we return immediately to get a "image not found" icon */ + tny_stream_close (stream); + return TRUE; + } + } else { + return FALSE; + } } tny_mime_part_decode_to_stream ((TnyMimePart*)part, stream, NULL); + tny_stream_close (stream); g_object_unref (G_OBJECT(part)); return TRUE; } static void -set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg) +set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg, TnyMimePart *other_body) { TnyMimePart *body; ModestGtkhtmlMsgViewPrivate *priv; TnyHeader *header; - GtkAdjustment *html_vadj; - + GtkAdjustment *html_vadj, *html_hadj; + g_return_if_fail (self); - + priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(self); + modest_mail_header_view_set_loading (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), FALSE); gtk_widget_set_no_show_all (priv->mail_header_view, FALSE); - - html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); - html_vadj->upper = 0; - html_vadj->page_size = 0; - g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); - + modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), FALSE); if (msg != priv->msg) { if (priv->msg) @@ -1476,14 +1769,34 @@ set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg) g_object_ref (G_OBJECT(msg)); priv->msg = msg; } - + if (!msg) { tny_header_view_clear (TNY_HEADER_VIEW (priv->mail_header_view)); modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL); gtk_widget_hide_all (priv->mail_header_view); gtk_widget_hide_all (priv->attachments_box); +#ifdef MODEST_TOOKIT_HILDON2 + gtk_widget_hide_all (priv->priority_box); +#endif gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view)); + + html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_vadj->upper = 0; + html_vadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); + + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_hadj->upper = 0; + html_hadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_hadj), "changed"); + + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1); + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1); + + priv->idle_changes_count = 0; + gtk_widget_queue_resize (GTK_WIDGET (priv->body_view)); + gtk_widget_queue_resize (GTK_WIDGET(self)); gtk_widget_queue_draw (GTK_WIDGET(self)); return; @@ -1493,27 +1806,81 @@ set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg) tny_header_view_set_header (TNY_HEADER_VIEW (priv->mail_header_view), header); g_object_unref (header); - modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW(priv->attachments_view), - msg); - - body = modest_tny_msg_find_body_part (msg, TRUE); + modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), + other_body?NULL:msg); + + modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), tny_msg_get_allow_external_images (msg)); + + if (other_body) { + body = other_body; + g_object_ref (body); + } else { + body = modest_tny_msg_find_body_part (msg, TRUE); + } if (body) { - tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), body); + ModestAttachmentsView *widget; - if(modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) { + tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), body); + g_object_unref (body); + widget = MODEST_ATTACHMENTS_VIEW (priv->attachments_view); + + if (modest_attachments_view_has_attachments (widget)) { + GtkLabel *label; + GList *children = NULL; + gchar *text = NULL; + /* Ugly but... */ + children = gtk_container_get_children (GTK_CONTAINER (priv->attachments_box)); + label = GTK_LABEL (children->data); gtk_widget_show_all (priv->attachments_box); +#ifdef MODEST_TOOLKIT_HILDON2 + if (modest_attachments_view_get_num_attachments (widget) > 1) { + text = _("mail_va_attachments"); + } else { + text = _("mail_va_attachment"); + } +#else + text = _("mail_va_attachment"); +#endif + gtk_label_set_text (label, text); } else { gtk_widget_hide_all (priv->attachments_box); } - } else + } else { tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view)); + } + + /* Refresh priority */ + set_priority (self, tny_header_get_flags (header)); gtk_widget_show (priv->body_view); +#ifdef MODEST_TOOLKIT_HILDON2 + gtk_widget_set_no_show_all (priv->priority_box, TRUE); +#endif gtk_widget_set_no_show_all (priv->attachments_box, TRUE); gtk_widget_show_all (priv->mail_header_view); gtk_widget_set_no_show_all (priv->attachments_box, FALSE); +#ifdef MODEST_TOOLKIT_HILDON2 + gtk_widget_set_no_show_all (priv->priority_box, FALSE); +#endif gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); + + html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_vadj->upper = 0; + html_vadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); + + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_hadj->upper = 0; + html_hadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_hadj), "changed"); + + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1); + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1); + + priv->idle_changes_count = 0; + gtk_widget_queue_resize (GTK_WIDGET (priv->body_view)); + gtk_widget_queue_resize (GTK_WIDGET(self)); gtk_widget_queue_draw (GTK_WIDGET(self)); @@ -1527,8 +1894,62 @@ set_message (ModestGtkhtmlMsgView *self, TnyMsg *msg) /* This is a hack to force reallocation of scroll after drawing all the stuff. This * makes the html view get the proper and expected size and prevent being able to scroll * the buffer when it shouldn't be scrollable */ - g_object_ref (self); - g_timeout_add (250, (GSourceFunc) idle_readjust_scroll, self); + if (priv->idle_readjust_scroll_id == 0) { + g_object_ref (self); + priv->idle_readjust_scroll_id = g_idle_add ((GSourceFunc) idle_readjust_scroll, self); + } +} + +static void +set_header (ModestGtkhtmlMsgView *self, TnyHeader *header) +{ + ModestGtkhtmlMsgViewPrivate *priv; + GtkAdjustment *html_vadj, *html_hadj; + + g_return_if_fail (self); + + if (header == NULL) { + set_message (self, NULL, NULL); + return; + } + + priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE(self); + modest_mail_header_view_set_loading (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), TRUE); + gtk_widget_set_no_show_all (priv->mail_header_view, FALSE); + modest_mime_part_view_set_view_images (MODEST_MIME_PART_VIEW (priv->body_view), FALSE); + + html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_vadj->upper = 0; + html_vadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); + + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_hadj->upper = 0; + html_hadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_hadj), "changed"); + + priv->idle_changes_count = 0; + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1); + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1); + gtk_widget_queue_resize (GTK_WIDGET (priv->body_view)); + + if (priv->msg) { + g_object_unref (G_OBJECT(priv->msg)); + } + priv->msg = NULL; + + tny_header_view_set_header (TNY_HEADER_VIEW (priv->mail_header_view), header); + modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL); + gtk_widget_show_all (priv->mail_header_view); + gtk_widget_hide_all (priv->attachments_box); +#ifdef MODEST_TOOLKIT_HILDON2 + gtk_widget_hide_all (priv->priority_box); +#endif + gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); + tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view)); + priv->idle_changes_count = 0; + gtk_widget_queue_resize (GTK_WIDGET(self)); + gtk_widget_queue_draw (GTK_WIDGET(self)); } @@ -1559,12 +1980,27 @@ static void set_zoom (ModestGtkhtmlMsgView *self, gdouble zoom) { ModestGtkhtmlMsgViewPrivate *priv; + GtkAdjustment *html_vadj, *html_hadj; g_return_if_fail (MODEST_IS_GTKHTML_MSG_VIEW (self)); priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); modest_zoomable_set_zoom (MODEST_ZOOMABLE(priv->body_view), zoom); + html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_vadj->upper = 0; + html_vadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_vadj), "changed"); + + html_hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll)); + html_hadj->upper = 0; + html_hadj->page_size = 0; + g_signal_emit_by_name (G_OBJECT (html_hadj), "changed"); + + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), 1, 1); + gtk_widget_set_size_request (GTK_WIDGET (priv->body_view), -1, -1); + + priv->idle_changes_count = 0; gtk_widget_queue_resize (priv->body_view); } @@ -1600,6 +2036,27 @@ set_priority (ModestGtkhtmlMsgView *self, TnyHeaderFlags flags) priv = MODEST_GTKHTML_MSG_VIEW_GET_PRIVATE (self); modest_mail_header_view_set_priority (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), flags); + +#ifdef MODEST_TOOLKIT_HILDON2 + gboolean show_priority = FALSE; + TnyHeaderFlags priority_flags; + + priority_flags = flags & TNY_HEADER_FLAG_PRIORITY_MASK; + if (priority_flags == TNY_HEADER_FLAG_HIGH_PRIORITY) { + show_priority = TRUE; + gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), MODEST_HEADER_ICON_HIGH, GTK_ICON_SIZE_MENU); + } else if (priority_flags == TNY_HEADER_FLAG_LOW_PRIORITY) { + show_priority = TRUE; + gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), MODEST_HEADER_ICON_LOW, GTK_ICON_SIZE_MENU); + } + + if (show_priority && MODEST_IS_COMPACT_MAIL_HEADER_VIEW (priv->mail_header_view)) { + gtk_widget_show_all (priv->priority_box); + } else { + gtk_widget_hide_all (priv->priority_box); + } +#endif + } /* INCREMENTAL SEARCH IMPLEMENTATION */ @@ -1722,6 +2179,45 @@ remove_attachment (ModestGtkhtmlMsgView *self, TnyMimePart *attachment) } +/* TNY HEADER VIEW IMPLEMENTATION */ + +static void +tny_header_view_init (gpointer g, gpointer iface_data) +{ + TnyHeaderViewIface *klass = (TnyHeaderViewIface *)g; + + klass->set_header = modest_msg_view_set_header; + klass->clear = modest_msg_view_clear_header; + + return; +} + +static void +modest_msg_view_set_header (TnyHeaderView *self, TnyHeader *header) +{ + MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_header_func (self, header); +} + + +static void +modest_msg_view_set_header_default (TnyHeaderView *self, TnyHeader *header) +{ + set_header (MODEST_GTKHTML_MSG_VIEW (self), header); +} + +static void +modest_msg_view_clear_header (TnyHeaderView *self) +{ + MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->clear_header_func (self); +} + + +static void +modest_msg_view_clear_header_default (TnyHeaderView *self) +{ + set_message (MODEST_GTKHTML_MSG_VIEW (self), NULL, NULL); +} + /* TNY MSG IMPLEMENTATION */ static void @@ -1789,7 +2285,7 @@ modest_msg_view_clear (TnyMsgView *self) static void modest_msg_view_clear_default (TnyMsgView *self) { - set_message (MODEST_GTKHTML_MSG_VIEW (self), NULL); + set_message (MODEST_GTKHTML_MSG_VIEW (self), NULL, NULL); } static TnyMimePartView* @@ -1859,7 +2355,7 @@ modest_msg_view_mp_set_part_default (TnyMimePartView *self, { g_return_if_fail ((part == NULL) || TNY_IS_MSG (part)); - set_message (MODEST_GTKHTML_MSG_VIEW (self), TNY_MSG (part)); + set_message (MODEST_GTKHTML_MSG_VIEW (self), TNY_MSG (part), NULL); } static void @@ -1998,6 +2494,7 @@ modest_msg_view_init (gpointer g, gpointer iface_data) { ModestMsgViewIface *klass = (ModestMsgViewIface *)g; + klass->set_msg_with_other_body_func = modest_gtkhtml_msg_view_set_msg_with_other_body; klass->get_vadjustment_func = modest_gtkhtml_msg_view_get_vadjustment; klass->get_hadjustment_func = modest_gtkhtml_msg_view_get_hadjustment; klass->set_vadjustment_func = modest_gtkhtml_msg_view_set_vadjustment; @@ -2010,10 +2507,25 @@ modest_msg_view_init (gpointer g, gpointer iface_data) klass->get_attachments_func = modest_gtkhtml_msg_view_get_attachments; klass->grab_focus_func = modest_gtkhtml_msg_view_grab_focus; klass->remove_attachment_func = modest_gtkhtml_msg_view_remove_attachment; + klass->request_fetch_images_func = modest_gtkhtml_msg_view_request_fetch_images; + klass->set_branding_func = modest_gtkhtml_msg_view_set_branding; + klass->has_blocked_external_images_func = modest_gtkhtml_msg_view_has_blocked_external_images; return; } +static void +modest_gtkhtml_msg_view_set_msg_with_other_body (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body) +{ + MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_msg_with_other_body_func (self, msg, other_body); +} + +static void +modest_gtkhtml_msg_view_set_msg_with_other_body_default (ModestMsgView *self, TnyMsg *msg, TnyMimePart *other_body) +{ + set_message (MODEST_GTKHTML_MSG_VIEW (self), msg, other_body); +} + static GtkAdjustment* modest_gtkhtml_msg_view_get_vadjustment (ModestMsgView *self) { @@ -2157,3 +2669,39 @@ modest_gtkhtml_msg_view_remove_attachment_default (ModestMsgView *self, TnyMimeP { remove_attachment (MODEST_GTKHTML_MSG_VIEW (self), attachment); } + +static void +modest_gtkhtml_msg_view_request_fetch_images (ModestMsgView *self) +{ + MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->request_fetch_images_func (self); +} + +static void +modest_gtkhtml_msg_view_request_fetch_images_default (ModestMsgView *self) +{ + request_fetch_images (MODEST_GTKHTML_MSG_VIEW (self)); +} + +static void +modest_gtkhtml_msg_view_set_branding (ModestMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon) +{ + MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->set_branding_func (self, brand_name, brand_icon); +} + +static void +modest_gtkhtml_msg_view_set_branding_default (ModestMsgView *self, const gchar *brand_name, const GdkPixbuf *brand_icon) +{ + set_branding (MODEST_GTKHTML_MSG_VIEW (self), brand_name, brand_icon); +} + +static gboolean +modest_gtkhtml_msg_view_has_blocked_external_images (ModestMsgView *self) +{ + return MODEST_GTKHTML_MSG_VIEW_GET_CLASS (self)->has_blocked_external_images_func (self); +} + +static gboolean +modest_gtkhtml_msg_view_has_blocked_external_images_default (ModestMsgView *self) +{ + return has_blocked_external_images (MODEST_GTKHTML_MSG_VIEW (self)); +}