1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <tny-gtk-text-buffer-stream.h>
35 #include <glib/gi18n.h>
37 #include <tny-simple-list.h>
39 #include <modest-tny-msg.h>
40 #include <modest-text-utils.h>
41 #include <widgets/modest-msg-view.h>
42 #include <widgets/modest-mail-header-view.h>
43 #include <widgets/modest-attachments-view.h>
44 #include <modest-marshal.h>
45 #include <widgets/modest-gtkhtml-mime-part-view.h>
46 #include <widgets/modest-isearch-view.h>
49 /* 'private'/'protected' functions */
50 static void modest_msg_view_class_init (ModestMsgViewClass *klass);
51 static void tny_msg_view_init (gpointer g, gpointer iface_data);
52 static void tny_mime_part_view_init (gpointer g, gpointer iface_data);
53 static void modest_zoomable_init (gpointer g, gpointer iface_data);
54 static void modest_msg_view_init (ModestMsgView *obj);
55 static void modest_msg_view_finalize (GObject *obj);
56 static void modest_msg_view_destroy (GtkObject *obj);
57 static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
58 static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
61 static void on_recpt_activated (ModestMailHeaderView *header_view, const gchar *address, ModestMsgView *msg_view);
62 static void on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer userdata);
64 /* body view signals */
65 static gboolean on_activate_link (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view);
66 static gboolean on_fetch_url (GtkWidget *widget, const gchar *uri, TnyStream *stream,
67 ModestMsgView *msg_view);
68 static gboolean on_link_hover (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view);
71 static void on_tap_and_hold (GtkWidget *widget, gpointer userdata);
72 #endif /*MAEMO_CHANGES*/
75 /* size allocation and drawing handlers */
76 static void get_view_allocation (ModestMsgView *msg_view, GtkAllocation *allocation);
77 static void size_request (GtkWidget *widget, GtkRequisition *req);
78 static void size_allocate (GtkWidget *widget, GtkAllocation *alloc);
79 static void realize (GtkWidget *widget);
80 static void unrealize (GtkWidget *widget);
81 static gint expose (GtkWidget *widget, GdkEventExpose *event);
82 static void reclamp_adjustment (GtkAdjustment *adj, gboolean *value_changed);
83 static void set_hadjustment_values (ModestMsgView *msg_view, gboolean *value_changed);
84 static void set_scroll_adjustments (ModestMsgView *msg_view, GtkAdjustment *hadj, GtkAdjustment *vadj);
85 static void adjustment_value_changed (GtkAdjustment *adj, gpointer data);
86 static void html_adjustment_changed (GtkAdjustment *adj, gpointer data);
87 static void disconnect_vadjustment (ModestMsgView *obj);
88 static void disconnect_hadjustment (ModestMsgView *obj);
89 static gboolean idle_readjust_scroll (ModestMsgView *obj);
91 /* GtkContainer methods */
92 static void forall (GtkContainer *container, gboolean include_internals,
93 GtkCallback callback, gpointer userdata);
94 static void container_remove (GtkContainer *container, GtkWidget *widget);
96 /* TnyMimePartView implementation */
97 static void modest_msg_view_mp_clear (TnyMimePartView *self);
98 static void modest_msg_view_mp_set_part (TnyMimePartView *self, TnyMimePart *part);
99 static void modest_msg_view_mp_set_part_default (TnyMimePartView *self, TnyMimePart *part);
100 static TnyMimePart* modest_msg_view_mp_get_part (TnyMimePartView *self);
101 static TnyMimePart* modest_msg_view_mp_get_part_default (TnyMimePartView *self);
102 /* TnyMsgView implementation */
103 static TnyMsg *modest_msg_view_get_msg (TnyMsgView *self);
104 static TnyMsg *modest_msg_view_get_msg_default (TnyMsgView *self);
105 static void modest_msg_view_set_msg (TnyMsgView *self, TnyMsg *msg);
106 static void modest_msg_view_set_msg_default (TnyMsgView *self, TnyMsg *msg);
107 static void modest_msg_view_clear (TnyMsgView *self);
108 static void modest_msg_view_clear_default (TnyMsgView *self);
109 static void modest_msg_view_set_unavailable (TnyMsgView *self);
110 static void modest_msg_view_set_unavailable_default (TnyMsgView *self);
111 static TnyMimePartView *modest_msg_view_create_mime_part_view_for (TnyMsgView *self, TnyMimePart *part);
112 static TnyMimePartView *modest_msg_view_create_mime_part_view_for_default (TnyMsgView *self, TnyMimePart *part);
113 static TnyMsgView *modest_msg_view_create_new_inline_viewer (TnyMsgView *self);
114 static TnyMsgView *modest_msg_view_create_new_inline_viewer_default (TnyMsgView *self);
115 /* ModestZoomable implementation */
116 static gdouble modest_msg_view_get_zoom (ModestZoomable *self);
117 static void modest_msg_view_set_zoom (ModestZoomable *self, gdouble value);
118 static gboolean modest_msg_view_zoom_minus (ModestZoomable *self);
119 static gboolean modest_msg_view_zoom_plus (ModestZoomable *self);
120 static gdouble modest_msg_view_get_zoom_default (ModestZoomable *self);
121 static void modest_msg_view_set_zoom_default (ModestZoomable *self, gdouble value);
122 static gboolean modest_msg_view_zoom_minus_default (ModestZoomable *self);
123 static gboolean modest_msg_view_zoom_plus_default (ModestZoomable *self);
126 static TnyMsg *get_message (ModestMsgView *self);
127 static void set_message (ModestMsgView *self, TnyMsg *tny_msg);
128 static void set_zoom (ModestMsgView *self, gdouble zoom);
129 static gdouble get_zoom (ModestMsgView *self);
132 /* list my signals */
136 ATTACHMENT_CLICKED_SIGNAL,
137 RECPT_ACTIVATED_SIGNAL,
138 LINK_CONTEXTUAL_SIGNAL,
142 /* list properties */
150 typedef struct _ModestMsgViewPrivate ModestMsgViewPrivate;
151 struct _ModestMsgViewPrivate {
152 GtkWidget *body_view;
153 GtkWidget *mail_header_view;
154 GtkWidget *attachments_view;
158 /* embedded elements */
159 GtkWidget *headers_box;
160 GtkWidget *html_scroll;
161 GtkWidget *attachments_box;
163 /* internal adjustments for set_scroll_adjustments */
166 GtkShadowType shadow_type;
168 /* gdk windows for drawing */
169 GdkWindow *view_window;
170 GdkWindow *headers_window;
171 GdkWindow *html_window;
174 gdouble current_zoom;
176 /* link click management */
179 TnyHeaderFlags priority_flags;
181 gulong sig1, sig2, sig3;
183 #define MODEST_MSG_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
184 MODEST_TYPE_MSG_VIEW, \
185 ModestMsgViewPrivate))
187 static GtkContainerClass *parent_class = NULL;
189 /* uncomment the following if you have defined any signals */
190 static guint signals[LAST_SIGNAL] = {0};
193 modest_msg_view_get_type (void)
195 static GType my_type = 0;
197 static const GTypeInfo my_info = {
198 sizeof(ModestMsgViewClass),
199 NULL, /* base init */
200 NULL, /* base finalize */
201 (GClassInitFunc) modest_msg_view_class_init,
202 NULL, /* class finalize */
203 NULL, /* class data */
204 sizeof(ModestMsgView),
206 (GInstanceInitFunc) modest_msg_view_init,
209 static const GInterfaceInfo tny_msg_view_info =
211 (GInterfaceInitFunc) tny_msg_view_init, /* interface_init */
212 NULL, /* interface_finalize */
213 NULL /* interface_data */
216 static const GInterfaceInfo tny_mime_part_view_info =
218 (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
219 NULL, /* interface_finalize */
220 NULL /* interface_data */
223 static const GInterfaceInfo modest_zoomable_info =
225 (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
226 NULL, /* interface_finalize */
227 NULL /* interface_data */
230 my_type = g_type_register_static (GTK_TYPE_CONTAINER,
234 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW,
235 &tny_mime_part_view_info);
237 g_type_add_interface_static (my_type, TNY_TYPE_MSG_VIEW,
240 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE,
241 &modest_zoomable_info);
247 modest_msg_view_class_init (ModestMsgViewClass *klass)
249 GObjectClass *gobject_class;
250 GtkWidgetClass *widget_class;
251 GtkObjectClass *gtkobject_class;
252 GtkContainerClass *container_class;
253 gobject_class = (GObjectClass*) klass;
254 widget_class = (GtkWidgetClass *) klass;
255 gtkobject_class = (GtkObjectClass *) klass;
256 container_class = (GtkContainerClass *) klass;
258 parent_class = g_type_class_peek_parent (klass);
259 gobject_class->finalize = modest_msg_view_finalize;
260 gobject_class->set_property = set_property;
261 gobject_class->get_property = get_property;
262 gtkobject_class->destroy = modest_msg_view_destroy;
264 widget_class->realize = realize;
265 widget_class->unrealize = unrealize;
266 widget_class->expose_event = expose;
267 widget_class->size_request = size_request;
268 widget_class->size_allocate = size_allocate;
270 container_class->forall = forall;
271 container_class->remove = container_remove;
273 klass->set_scroll_adjustments = set_scroll_adjustments;
274 klass->get_part_func = modest_msg_view_mp_get_part_default;
275 klass->set_part_func = modest_msg_view_mp_set_part_default;
276 klass->get_msg_func = modest_msg_view_get_msg_default;
277 klass->set_msg_func = modest_msg_view_set_msg_default;
278 klass->set_unavailable_func = modest_msg_view_set_unavailable_default;
279 klass->clear_func = modest_msg_view_clear_default;
280 klass->create_mime_part_view_for_func = modest_msg_view_create_mime_part_view_for_default;
281 klass->create_new_inline_viewer_func = modest_msg_view_create_new_inline_viewer_default;
282 klass->get_zoom_func = modest_msg_view_get_zoom_default;
283 klass->set_zoom_func = modest_msg_view_set_zoom_default;
284 klass->zoom_minus_func = modest_msg_view_zoom_minus_default;
285 klass->zoom_plus_func = modest_msg_view_zoom_plus_default;
287 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewPrivate));
289 g_object_class_install_property (gobject_class,
291 g_param_spec_object ("hadjustment",
292 _("Horizontal adjustment"),
293 _("GtkAdjustment with information of the horizontal visible position"),
295 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
297 g_object_class_install_property (gobject_class,
299 g_param_spec_object ("vadjustment",
300 _("Vertical adjustment"),
301 _("GtkAdjustment with information of the vertical visible position"),
303 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
305 g_object_class_install_property (gobject_class,
307 g_param_spec_enum ("shadow_type",
309 _("Kind of shadow that's shown around the view"),
310 GTK_TYPE_SHADOW_TYPE,
312 G_PARAM_READABLE | G_PARAM_WRITABLE ));
314 signals[LINK_CLICKED_SIGNAL] =
315 g_signal_new ("link_clicked",
316 G_TYPE_FROM_CLASS (gobject_class),
318 G_STRUCT_OFFSET(ModestMsgViewClass, link_clicked),
320 g_cclosure_marshal_VOID__STRING,
321 G_TYPE_NONE, 1, G_TYPE_STRING);
323 signals[ATTACHMENT_CLICKED_SIGNAL] =
324 g_signal_new ("attachment_clicked",
325 G_TYPE_FROM_CLASS (gobject_class),
327 G_STRUCT_OFFSET(ModestMsgViewClass, attachment_clicked),
329 g_cclosure_marshal_VOID__OBJECT,
330 G_TYPE_NONE, 1, G_TYPE_OBJECT);
332 signals[LINK_HOVER_SIGNAL] =
333 g_signal_new ("link_hover",
334 G_TYPE_FROM_CLASS (gobject_class),
336 G_STRUCT_OFFSET(ModestMsgViewClass, link_hover),
338 g_cclosure_marshal_VOID__STRING,
339 G_TYPE_NONE, 1, G_TYPE_STRING);
341 signals[RECPT_ACTIVATED_SIGNAL] =
342 g_signal_new ("recpt_activated",
343 G_TYPE_FROM_CLASS (gobject_class),
345 G_STRUCT_OFFSET(ModestMsgViewClass, recpt_activated),
347 g_cclosure_marshal_VOID__STRING,
348 G_TYPE_NONE, 1, G_TYPE_STRING);
350 signals[LINK_CONTEXTUAL_SIGNAL] =
351 g_signal_new ("link_contextual",
352 G_TYPE_FROM_CLASS (gobject_class),
354 G_STRUCT_OFFSET(ModestMsgViewClass, link_contextual),
356 g_cclosure_marshal_VOID__STRING,
357 G_TYPE_NONE, 1, G_TYPE_STRING);
359 widget_class->set_scroll_adjustments_signal =
360 g_signal_new ("set_scroll_adjustments",
361 G_OBJECT_CLASS_TYPE (gobject_class),
362 G_SIGNAL_RUN_LAST|G_SIGNAL_ACTION,
363 G_STRUCT_OFFSET (ModestMsgViewClass, set_scroll_adjustments),
365 modest_marshal_VOID__POINTER_POINTER,
368 GTK_TYPE_ADJUSTMENT);
372 set_property (GObject *object,
377 ModestMsgView *msg_view = MODEST_MSG_VIEW (object);
380 case PROP_HADJUSTMENT:
381 modest_msg_view_set_hadjustment (msg_view, g_value_get_object (value));
383 case PROP_VADJUSTMENT:
384 modest_msg_view_set_vadjustment (msg_view, g_value_get_object (value));
386 case PROP_SHADOW_TYPE:
387 modest_msg_view_set_shadow_type (msg_view, g_value_get_enum (value));
390 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
396 get_property (GObject *object,
401 ModestMsgView *msg_view = MODEST_MSG_VIEW (object);
402 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
405 case PROP_HADJUSTMENT:
406 g_value_set_object (value, priv->hadj);
408 case PROP_VADJUSTMENT:
409 g_value_set_object (value, priv->vadj);
411 case PROP_SHADOW_TYPE:
412 g_value_set_enum (value, priv->shadow_type);
415 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
421 disconnect_hadjustment (ModestMsgView *msg_view)
423 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
426 g_signal_handlers_disconnect_by_func(priv->hadj, adjustment_value_changed, msg_view);
427 g_object_unref (priv->hadj);
433 disconnect_vadjustment (ModestMsgView *msg_view)
435 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
438 g_signal_handlers_disconnect_by_func(priv->vadj, adjustment_value_changed, msg_view);
439 g_object_unref (priv->vadj);
445 get_view_allocation (ModestMsgView *msg_view, GtkAllocation *allocation)
447 /* This method gets the allocation of the widget in parent widget. It's the
448 real position and size of the widget */
449 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
454 if (priv->shadow_type != GTK_SHADOW_NONE) {
455 allocation->x = GTK_WIDGET (msg_view)->style->xthickness;
456 allocation->y = GTK_WIDGET (msg_view)->style->ythickness;
459 allocation->width = MAX (1, (GTK_WIDGET (msg_view)->allocation.width) - allocation->x * 2);
460 allocation->height = MAX (1, (GTK_WIDGET (msg_view)->allocation.height) - allocation->y * 2);
465 reclamp_adjustment (GtkAdjustment *adj,
466 gboolean *value_changed)
468 gdouble value = adj->value;
470 /* Correct value to be inside the expected values of a scroll */
472 value = CLAMP (value, 0, adj->upper - adj->page_size);
474 if (value != adj->value) {
477 *value_changed = TRUE;
478 } else if (value_changed) {
479 *value_changed = FALSE;
484 set_hadjustment_values (ModestMsgView *msg_view,
485 gboolean *value_changed)
487 GtkAllocation view_allocation;
488 GtkAdjustment *hadj = modest_msg_view_get_hadjustment (msg_view);
490 get_view_allocation (msg_view, &view_allocation);
491 hadj->page_size = view_allocation.width;
492 hadj->step_increment = view_allocation.width * 0.1;
493 hadj->page_increment = view_allocation.width * 0.9;
496 hadj->upper = view_allocation.width;
498 reclamp_adjustment (hadj, value_changed);
503 set_vadjustment_values (ModestMsgView *msg_view,
504 gboolean *value_changed)
506 GtkAllocation view_allocation;
507 GtkAdjustment *vadj = modest_msg_view_get_vadjustment (msg_view);
508 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
509 gint full_height = 0;
510 GtkAdjustment *html_vadj;
512 get_view_allocation (msg_view, &view_allocation);
513 vadj->page_size = view_allocation.height;
514 vadj->step_increment = view_allocation.height * 0.1;
515 vadj->page_increment = view_allocation.height * 0.9;
519 if (priv->headers_box && GTK_WIDGET_VISIBLE(priv->headers_box)) {
520 GtkRequisition child_requisition;
522 gtk_widget_get_child_requisition (priv->headers_box, &child_requisition);
523 full_height = child_requisition.height;
528 /* Get the real height of the embedded html */
529 if (priv->html_scroll && GTK_WIDGET_VISIBLE(priv->html_scroll)) {
530 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
531 full_height += html_vadj->upper;
534 vadj->upper = MAX (view_allocation.height, full_height);
536 reclamp_adjustment (vadj, value_changed);
541 set_scroll_adjustments (ModestMsgView *msg_view,
545 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
546 modest_msg_view_set_hadjustment (msg_view, hadj);
547 modest_msg_view_set_vadjustment (msg_view, vadj);
549 gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->body_view), vadj);
553 realize (GtkWidget *widget)
555 ModestMsgView *msg_view = MODEST_MSG_VIEW (widget);
556 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
557 GtkAdjustment *hadj = modest_msg_view_get_hadjustment (msg_view);
558 GtkAdjustment *vadj = modest_msg_view_get_vadjustment (msg_view);
559 GdkWindowAttr attributes;
561 gint attributes_mask;
562 GtkAllocation view_allocation;
564 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
566 /* The structure of the GdkWindow's is:
567 * * widget->window: the shown gdkwindow embedding all the stuff inside
568 * * view_window: a backing store gdkwindow containing the headers and contents
569 * being scrolled. This window should have all the visible and non visible
571 * * headers_window: gdk window for headers_box.
572 * * html_window: gdk window for html_scroll (the scrolled window containing the
573 * body view showing the contents of the mail).
576 attributes.x = widget->allocation.x;
577 attributes.y = widget->allocation.y;
578 attributes.width = widget->allocation.width;
579 attributes.height = widget->allocation.height;
580 attributes.window_type = GDK_WINDOW_CHILD;
581 attributes.wclass = GDK_INPUT_OUTPUT;
582 attributes.visual = gtk_widget_get_visual (widget);
583 attributes.colormap = gtk_widget_get_colormap (widget);
585 event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
586 attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
587 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
589 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
590 &attributes, attributes_mask);
591 gdk_window_set_user_data (widget->window, msg_view);
593 get_view_allocation (msg_view, &view_allocation);
595 attributes.x = view_allocation.x;
596 attributes.y = view_allocation.y;
597 attributes.width = view_allocation.width;
598 attributes.height = view_allocation.height;
599 attributes.event_mask = 0;
600 priv->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
601 gdk_window_set_user_data (priv->view_window, msg_view);
602 gdk_window_set_back_pixmap (priv->view_window, NULL, FALSE);
604 attributes.x = -hadj->value;
605 attributes.y = -vadj->value;
606 attributes.width = hadj->upper;
607 if (priv->headers_box)
608 attributes.height = GTK_WIDGET (priv->headers_box)->allocation.height;
610 attributes.height = 1;
611 attributes.event_mask = event_mask;
613 priv->headers_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
614 gdk_window_set_user_data (priv->headers_window, msg_view);
616 if (priv->headers_box)
617 gtk_widget_set_parent_window (priv->headers_box, priv->headers_window);
619 attributes.x = -hadj->value;
620 if (priv->headers_box)
621 attributes.y = GTK_WIDGET (priv->headers_box)->allocation.height - vadj->value;
623 attributes.y = -vadj->value;
624 attributes.width = hadj->upper;
625 if (priv->headers_box)
626 attributes.height = vadj->upper - GTK_WIDGET (priv->headers_box)->allocation.height;
628 attributes.height = vadj->upper;
629 attributes.event_mask = event_mask;
631 priv->html_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
632 gdk_window_set_user_data (priv->html_window, msg_view);
634 if (priv->html_scroll)
635 gtk_widget_set_parent_window (priv->html_scroll, priv->html_window);
637 widget->style = gtk_style_attach (widget->style, widget->window);
638 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
639 gtk_style_set_background (widget->style, priv->headers_window, GTK_STATE_NORMAL);
640 gtk_style_set_background (widget->style, priv->html_window, GTK_STATE_NORMAL);
642 gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
644 NULL, widget, "msgviewheaders",
646 gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
648 NULL, widget, "msgviewcontents",
651 gdk_window_show (priv->view_window);
652 gdk_window_show (priv->headers_window);
653 gdk_window_show (priv->html_window);
658 unrealize (GtkWidget *widget)
660 ModestMsgView *msg_view = MODEST_MSG_VIEW (widget);
661 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
663 gdk_window_set_user_data (priv->view_window, NULL);
664 gdk_window_destroy (priv->view_window);
665 priv->view_window = NULL;
667 gdk_window_set_user_data (priv->headers_window, NULL);
668 gdk_window_destroy (priv->headers_window);
669 priv->headers_window = NULL;
671 gdk_window_set_user_data (priv->html_window, NULL);
672 gdk_window_destroy (priv->html_window);
673 priv->html_window = NULL;
675 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
676 ( * GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
681 expose (GtkWidget *widget,
682 GdkEventExpose *event)
684 ModestMsgView *msg_view;
685 ModestMsgViewPrivate *priv;
687 if (GTK_WIDGET_DRAWABLE (widget)) {
688 msg_view = MODEST_MSG_VIEW (widget);
689 priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
690 if (event->window == widget->window) {
691 gtk_paint_shadow (widget->style, widget->window,
692 GTK_STATE_NORMAL, priv->shadow_type,
693 &event->area, widget, "msgview",
695 } else if (event->window == priv->headers_window) {
696 gtk_paint_flat_box(widget->style, priv->headers_window, GTK_STATE_NORMAL,
698 &event->area, widget, "msgviewheaders",
700 } else if (event->window == priv->html_window) {
701 gtk_paint_flat_box(widget->style, priv->html_window, GTK_STATE_NORMAL,
703 &event->area, widget, "msgviewcontents",
706 if (priv->headers_box)
707 gtk_container_propagate_expose (GTK_CONTAINER (msg_view), priv->headers_box, event);
708 if (priv->html_scroll)
709 gtk_container_propagate_expose (GTK_CONTAINER (msg_view), priv->html_scroll, event);
710 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
717 forall (GtkContainer *container,
718 gboolean include_internals,
719 GtkCallback callback,
722 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (container);
723 g_return_if_fail (callback != NULL);
725 if (priv->headers_box)
726 (*callback) (priv->headers_box, userdata);
727 if (priv->html_scroll)
728 (*callback) (priv->html_scroll, userdata);
732 container_remove (GtkContainer *container,
735 gboolean was_visible = FALSE;
736 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (container);
737 was_visible = GTK_WIDGET_VISIBLE (widget);
738 if (widget == priv->headers_box) {
739 gtk_widget_unparent (priv->headers_box);
740 priv->headers_box = NULL;
741 } else if (widget == priv->html_scroll) {
742 gtk_widget_unparent (priv->html_scroll);
743 priv->html_scroll = NULL;
748 gtk_widget_queue_resize (GTK_WIDGET(container));
753 size_request (GtkWidget *widget,
756 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (widget);
757 GtkRequisition child_req;
762 gtk_widget_size_request (priv->headers_box, &child_req);
763 req->width = child_req.width;
764 req->height += child_req.height;
765 gtk_widget_size_request (priv->html_scroll, &child_req);
766 req->width = MAX (child_req.width, req->width);
767 req->height += child_req.height;
772 size_allocate (GtkWidget *widget,
773 GtkAllocation *allocation)
775 ModestMsgView *msg_view = MODEST_MSG_VIEW (widget);
776 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
777 gboolean hadj_value_changed, vadj_value_changed;
778 GtkAllocation headers_allocation, html_allocation, view_allocation;
779 GtkAdjustment *html_vadj;
781 if (GTK_WIDGET_MAPPED (widget) &&
782 priv->shadow_type != GTK_SHADOW_NONE &&
783 (allocation->width != widget->allocation.width ||
784 allocation->height != widget->allocation.height))
785 gdk_window_invalidate_rect (widget->window, NULL, FALSE);
787 widget->allocation = *allocation;
788 set_hadjustment_values (msg_view, &hadj_value_changed);
789 set_vadjustment_values (msg_view, &vadj_value_changed);
791 get_view_allocation (msg_view, &view_allocation);
793 headers_allocation.x = 0;
794 headers_allocation.y = 0;
795 headers_allocation.width = view_allocation.width;
796 if (priv->headers_box)
797 headers_allocation.height = GTK_WIDGET (priv->headers_box)->requisition.height;
799 headers_allocation.height = 0;
801 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
803 html_allocation.x = 0;
804 html_allocation.y = headers_allocation.height;
805 html_allocation.width = view_allocation.width;
806 html_allocation.height = MAX ((gint) html_vadj->upper, (gint)(priv->vadj->upper - headers_allocation.height));
808 if (GTK_WIDGET_REALIZED (widget)) {
809 gdk_window_move_resize (widget->window,
815 gdk_window_move_resize (priv->view_window,
818 view_allocation.width,
819 view_allocation.height);
820 gdk_window_move_resize (priv->headers_window,
822 (gint) (- priv->vadj->value),
824 headers_allocation.height);
825 gdk_window_move_resize (priv->html_window,
826 (gint) (- priv->hadj->value),
827 (gint) (html_allocation.y - priv->vadj->value),
828 (gint) priv->hadj->upper,
829 html_allocation.height);
832 if (priv->headers_box && GTK_WIDGET_VISIBLE (priv->headers_box)) {
833 gtk_widget_size_allocate (priv->headers_box, &headers_allocation);
835 if (priv->html_scroll && GTK_WIDGET_VISIBLE (priv->html_scroll)) {
836 html_allocation.x = 0;
837 html_allocation.y = 0;
838 html_allocation.width = (gint) priv->hadj->upper;
839 html_allocation.height = (gint) priv->vadj->upper - headers_allocation.height;
840 gtk_widget_size_allocate (priv->html_scroll, &html_allocation);
842 gtk_adjustment_changed (priv->hadj);
843 gtk_adjustment_changed (priv->vadj);
845 if (hadj_value_changed)
846 gtk_adjustment_value_changed (priv->hadj);
847 if (vadj_value_changed)
848 gtk_adjustment_value_changed (priv->vadj);
853 adjustment_value_changed (GtkAdjustment *adj, gpointer data)
855 ModestMsgView *msg_view = NULL;
856 ModestMsgViewPrivate *priv = NULL;
858 g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
859 g_return_if_fail (MODEST_IS_MSG_VIEW (data));
861 msg_view = MODEST_MSG_VIEW (data);
862 priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
864 if (GTK_WIDGET_REALIZED (msg_view)) {
865 GtkAdjustment *hadj = modest_msg_view_get_hadjustment (msg_view);
866 GtkAdjustment *vadj = modest_msg_view_get_vadjustment (msg_view);
867 gint headers_offset = 0;
869 gtk_widget_queue_resize (priv->html_scroll);
871 if (priv->headers_box && GTK_WIDGET_VISIBLE (priv->headers_box)) {
874 gdk_window_get_position (priv->headers_window, &old_x, &old_y);
876 new_y = -vadj->value;
878 headers_offset = GTK_WIDGET(priv->headers_box)->allocation.height;
880 if (new_x != old_x || new_y != old_y) {
881 gdk_window_move (priv->headers_window, new_x, new_y);
882 gdk_window_process_updates (priv->headers_window, TRUE);
886 if (priv->html_scroll && GTK_WIDGET_VISIBLE (priv->html_scroll)) {
889 gdk_window_get_position (priv->html_window, &old_x, &old_y);
890 new_x = -hadj->value;
891 new_y = headers_offset - vadj->value;
893 if (new_x != old_x || new_y != old_y) {
894 gdk_window_move (priv->html_window, new_x, new_y);
895 gdk_window_process_updates (priv->html_window, TRUE);
903 html_adjustment_changed (GtkAdjustment *adj,
906 ModestMsgView *msg_view = MODEST_MSG_VIEW (userdata);
907 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
908 GtkAdjustment *html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(priv->html_scroll));
909 gboolean vadj_changed;
912 g_signal_stop_emission_by_name (G_OBJECT (adj), "changed");
914 priv->html_scroll->requisition.height = html_vadj->upper;
915 if (html_vadj->upper == priv->html_scroll->allocation.height)
917 priv->html_scroll->allocation.height = html_vadj->upper;
919 set_vadjustment_values (msg_view, &vadj_changed);
921 new_height = MAX ((gint) html_vadj->upper, (gint) (priv->vadj->upper - priv->headers_box->allocation.height));
923 gtk_adjustment_changed (priv->vadj);
924 if (GTK_WIDGET_DRAWABLE (priv->html_scroll)) {
925 gdk_window_resize (priv->html_window, (gint) priv->hadj->upper, (gint) new_height);
926 gdk_window_process_updates (priv->view_window, TRUE);
927 gtk_container_resize_children (GTK_CONTAINER (msg_view));
933 modest_msg_view_init (ModestMsgView *obj)
935 ModestMsgViewPrivate *priv;
936 GtkAdjustment *html_vadj;
937 GtkWidget *separator;
939 GTK_WIDGET_UNSET_FLAGS (obj, GTK_NO_WINDOW);
940 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (obj), TRUE);
941 gtk_container_set_reallocate_redraws (GTK_CONTAINER (obj), TRUE);
942 gtk_container_set_resize_mode (GTK_CONTAINER (obj), GTK_RESIZE_QUEUE);
944 priv = MODEST_MSG_VIEW_GET_PRIVATE(obj);
946 priv->current_zoom = 1.0;
947 priv->priority_flags = 0;
951 priv->shadow_type = GTK_SHADOW_IN;
952 priv->view_window = NULL;
953 priv->headers_window = NULL;
954 priv->html_window = NULL;
956 gtk_widget_push_composite_child ();
957 priv->html_scroll = gtk_scrolled_window_new (NULL, NULL);
958 gtk_widget_set_composite_name (priv->html_scroll, "contents");
959 gtk_widget_pop_composite_child ();
960 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->html_scroll), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
964 priv->body_view = GTK_WIDGET (g_object_new (MODEST_TYPE_GTKHTML_MIME_PART_VIEW, NULL));
965 priv->mail_header_view = GTK_WIDGET(modest_mail_header_view_new (TRUE));
966 gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
968 priv->attachments_view = GTK_WIDGET(modest_attachments_view_new (NULL));
970 priv->sig1 = g_signal_connect (G_OBJECT(priv->body_view), "activate_link",
971 G_CALLBACK(on_activate_link), obj);
972 priv->sig2 = g_signal_connect (G_OBJECT(priv->body_view), "fetch_url",
973 G_CALLBACK(on_fetch_url), obj);
974 priv->sig3 = g_signal_connect (G_OBJECT(priv->body_view), "link_hover",
975 G_CALLBACK(on_link_hover), obj);
977 g_signal_connect (G_OBJECT (priv->mail_header_view), "recpt-activated",
978 G_CALLBACK (on_recpt_activated), obj);
980 g_signal_connect (G_OBJECT (priv->attachments_view), "activate",
981 G_CALLBACK (on_attachment_activated), obj);
983 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(priv->html_scroll));
985 g_signal_connect (G_OBJECT (html_vadj), "changed",
986 G_CALLBACK (html_adjustment_changed), obj);
988 gtk_widget_push_composite_child ();
989 priv->headers_box = gtk_vbox_new (0, FALSE);
990 gtk_widget_set_composite_name (priv->headers_box, "headers");
991 gtk_widget_pop_composite_child ();
993 if (priv->mail_header_view)
994 gtk_box_pack_start (GTK_BOX(priv->headers_box), priv->mail_header_view, FALSE, FALSE, 0);
996 if (priv->attachments_view) {
997 gchar *att_label = g_strconcat (_("mcen_me_viewer_attachments"), ":", NULL);
999 priv->attachments_box = (GtkWidget *)
1000 modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view),
1002 priv->attachments_view,
1004 gtk_widget_hide_all (priv->attachments_box);
1008 separator = gtk_hseparator_new ();
1009 gtk_box_pack_start (GTK_BOX(priv->headers_box), separator, FALSE, FALSE, 0);
1011 gtk_widget_set_parent (priv->headers_box, GTK_WIDGET (obj));
1013 if (priv->body_view) {
1014 gtk_container_add (GTK_CONTAINER (priv->html_scroll), priv->body_view);
1015 gtk_widget_set_parent (priv->html_scroll, GTK_WIDGET(obj));
1016 #ifdef MAEMO_CHANGES
1017 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->body_view), NULL, NULL, 0);
1018 g_signal_connect (G_OBJECT (priv->body_view), "tap-and-hold", G_CALLBACK (on_tap_and_hold), obj);
1026 modest_msg_view_finalize (GObject *obj)
1028 ModestMsgViewPrivate *priv;
1029 priv = MODEST_MSG_VIEW_GET_PRIVATE (obj);
1032 g_object_unref (G_OBJECT(priv->msg));
1036 /* we cannot disconnect sigs, because priv->body_view is
1039 disconnect_vadjustment (MODEST_MSG_VIEW(obj));
1040 disconnect_hadjustment (MODEST_MSG_VIEW(obj));
1042 priv->body_view = NULL;
1043 priv->attachments_view = NULL;
1045 G_OBJECT_CLASS(parent_class)->finalize (obj);
1049 modest_msg_view_destroy (GtkObject *obj)
1051 disconnect_vadjustment (MODEST_MSG_VIEW(obj));
1052 disconnect_hadjustment (MODEST_MSG_VIEW(obj));
1054 GTK_OBJECT_CLASS(parent_class)->destroy (obj);
1058 modest_msg_view_get_vadjustment (ModestMsgView *msg_view)
1060 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1063 modest_msg_view_set_vadjustment (msg_view, NULL);
1070 modest_msg_view_get_hadjustment (ModestMsgView *msg_view)
1072 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1075 modest_msg_view_set_hadjustment (msg_view, NULL);
1082 modest_msg_view_set_hadjustment (ModestMsgView *msg_view, GtkAdjustment *hadj)
1084 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1085 gboolean value_changed;
1087 if (hadj && hadj == priv->hadj)
1091 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,0.0,0.0,0.0,0.0,0.0));
1092 disconnect_hadjustment (msg_view);
1093 g_object_ref (G_OBJECT (hadj));
1094 gtk_object_sink (GTK_OBJECT (hadj));
1096 set_hadjustment_values (msg_view, &value_changed);
1098 g_signal_connect (hadj, "value_changed", G_CALLBACK (adjustment_value_changed),
1101 gtk_adjustment_changed (hadj);
1103 gtk_adjustment_value_changed (hadj);
1105 adjustment_value_changed (hadj, msg_view);
1107 g_object_notify (G_OBJECT (msg_view), "hadjustment");
1111 modest_msg_view_set_vadjustment (ModestMsgView *msg_view, GtkAdjustment *vadj)
1113 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1114 gboolean value_changed;
1116 if (vadj && vadj == priv->vadj)
1120 vadj = (GtkAdjustment *) gtk_adjustment_new (0.0,0.0,0.0,0.0,0.0,0.0);
1121 disconnect_vadjustment (msg_view);
1122 g_object_ref (G_OBJECT (vadj));
1123 gtk_object_sink (GTK_OBJECT (vadj));
1125 set_vadjustment_values (msg_view, &value_changed);
1127 g_signal_connect (vadj, "value_changed", G_CALLBACK (adjustment_value_changed),
1130 gtk_adjustment_changed (vadj);
1132 gtk_adjustment_value_changed (vadj);
1134 adjustment_value_changed (vadj, msg_view);
1136 g_object_notify (G_OBJECT (msg_view), "vadjustment");
1140 * modest_msg_view_set_shadow_type:
1141 * @msg_view: a #ModestMsgView.
1142 * @shadow_type: new shadow type.
1144 * Sets a shadow type of the message view.
1147 modest_msg_view_set_shadow_type (ModestMsgView *msg_view,
1148 GtkShadowType shadow_type)
1150 ModestMsgViewPrivate *priv;
1151 g_return_if_fail (MODEST_IS_MSG_VIEW (msg_view));
1153 priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1155 if (priv->shadow_type != shadow_type) {
1156 priv->shadow_type = shadow_type;
1158 if (GTK_WIDGET_VISIBLE (msg_view)) {
1159 gtk_widget_size_allocate (GTK_WIDGET (msg_view), &(GTK_WIDGET (msg_view)->allocation));
1160 gtk_widget_queue_draw (GTK_WIDGET (msg_view));
1162 g_object_notify (G_OBJECT (msg_view), "shadow-type");
1167 * modest_msg_view_get_shadow_type:
1168 * @msg_view: a #ModestMsgView
1170 * Gets the current shadow type of the #ModestMsgView.
1172 * Return value: the shadow type
1175 modest_msg_view_get_shadow_type (ModestMsgView *msg_view)
1177 ModestMsgViewPrivate *priv;
1178 g_return_val_if_fail (MODEST_IS_MSG_VIEW (msg_view), GTK_SHADOW_NONE);
1179 priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1181 return priv->shadow_type;
1185 modest_msg_view_new (TnyMsg *msg)
1188 ModestMsgView* self;
1190 obj = G_OBJECT(g_object_new(MODEST_TYPE_MSG_VIEW, NULL));
1191 self = MODEST_MSG_VIEW(obj);
1192 tny_msg_view_set_msg (TNY_MSG_VIEW (self), msg);
1194 return GTK_WIDGET(self);
1197 #ifdef MAEMO_CHANGES
1199 on_tap_and_hold (GtkWidget *widget,
1202 ModestMsgView *msg_view = (ModestMsgView *) data;
1203 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1205 g_signal_emit (G_OBJECT (msg_view), signals[LINK_CONTEXTUAL_SIGNAL],
1211 on_recpt_activated (ModestMailHeaderView *header_view,
1212 const gchar *address,
1213 ModestMsgView * view)
1215 g_signal_emit (G_OBJECT (view), signals[RECPT_ACTIVATED_SIGNAL], 0, address);
1219 on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer msg_view)
1222 g_signal_emit (G_OBJECT(msg_view), signals[ATTACHMENT_CLICKED_SIGNAL],
1227 on_activate_link (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view)
1229 g_return_val_if_fail (msg_view, FALSE);
1231 g_signal_emit (G_OBJECT(msg_view), signals[LINK_CLICKED_SIGNAL],
1239 on_link_hover (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view)
1241 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1243 g_free (priv->last_url);
1244 priv->last_url = g_strdup (uri);
1246 g_signal_emit (G_OBJECT(msg_view), signals[LINK_HOVER_SIGNAL],
1254 static TnyMimePart *
1255 find_cid_image (TnyMsg *msg, const gchar *cid)
1257 TnyMimePart *part = NULL;
1261 g_return_val_if_fail (msg, NULL);
1262 g_return_val_if_fail (cid, NULL);
1264 parts = TNY_LIST (tny_simple_list_new());
1266 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1267 iter = tny_list_create_iterator (parts);
1269 while (!tny_iterator_is_done(iter)) {
1270 const gchar *part_cid;
1272 part = TNY_MIME_PART(tny_iterator_get_current(iter));
1273 part_cid = tny_mime_part_get_content_id (part);
1275 if (part_cid && strcmp (cid, part_cid) == 0)
1278 if (tny_mime_part_content_type_is (part, "multipart/related")) {
1279 TnyList *related_parts = TNY_LIST (tny_simple_list_new ());
1280 TnyIterator *related_iter = NULL;
1281 TnyMimePart *related_part = NULL;
1283 tny_mime_part_get_parts (part, related_parts);
1284 related_iter = tny_list_create_iterator (related_parts);
1286 while (!tny_iterator_is_done (related_iter)) {
1287 related_part = TNY_MIME_PART (tny_iterator_get_current (related_iter));
1288 part_cid = tny_mime_part_get_content_id (related_part);
1289 if (part_cid && strcmp (cid, part_cid) == 0) {
1292 g_object_unref (related_part);
1293 related_part = NULL;
1294 tny_iterator_next (related_iter);
1297 g_object_unref (related_iter);
1298 g_object_unref (related_parts);
1299 if (related_part != NULL) {
1300 g_object_unref (part);
1301 part = related_part;
1306 g_object_unref (G_OBJECT(part));
1309 tny_iterator_next (iter);
1312 g_object_unref (G_OBJECT(iter));
1313 g_object_unref (G_OBJECT(parts));
1320 on_fetch_url (GtkWidget *widget, const gchar *uri,
1321 TnyStream *stream, ModestMsgView *msg_view)
1323 ModestMsgViewPrivate *priv;
1324 priv = MODEST_MSG_VIEW_GET_PRIVATE (msg_view);
1325 gboolean result = FALSE;
1327 if (g_str_has_prefix (uri, "cid:")) {
1328 /* +4 ==> skip "cid:" */
1329 TnyMimePart *part = find_cid_image (priv->msg, uri + 4);
1331 g_printerr ("modest: '%s' not found\n", uri + 4);
1334 tny_mime_part_decode_to_stream ((TnyMimePart*)part,
1336 g_object_unref (G_OBJECT(part));
1347 set_message (ModestMsgView *self, TnyMsg *msg)
1350 ModestMsgViewPrivate *priv;
1352 GtkAdjustment *html_vadj;
1354 g_return_if_fail (self);
1356 priv = MODEST_MSG_VIEW_GET_PRIVATE(self);
1357 gtk_widget_set_no_show_all (priv->mail_header_view, FALSE);
1359 if (msg != priv->msg) {
1361 g_object_unref (G_OBJECT(priv->msg));
1363 g_object_ref (G_OBJECT(msg));
1368 tny_header_view_clear (TNY_HEADER_VIEW (priv->mail_header_view));
1369 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL);
1370 gtk_widget_hide_all (priv->mail_header_view);
1371 gtk_widget_hide_all (priv->attachments_box);
1372 gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1373 tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view));
1374 gtk_widget_queue_resize (GTK_WIDGET(self));
1375 gtk_widget_queue_draw (GTK_WIDGET(self));
1379 header = tny_msg_get_header (msg);
1380 tny_header_view_set_header (TNY_HEADER_VIEW (priv->mail_header_view), header);
1381 g_object_unref (header);
1383 modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW(priv->attachments_view),
1386 body = modest_tny_msg_find_body_part (msg, TRUE);
1388 tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (priv->body_view), body);
1390 if(modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) {
1391 gtk_widget_show_all (priv->attachments_box);
1393 gtk_widget_hide_all (priv->attachments_box);
1397 tny_mime_part_view_clear (TNY_MIME_PART_VIEW (priv->body_view));
1399 gtk_widget_show (priv->body_view);
1400 gtk_widget_set_no_show_all (priv->attachments_box, TRUE);
1401 gtk_widget_show_all (priv->mail_header_view);
1402 gtk_widget_set_no_show_all (priv->attachments_box, FALSE);
1403 gtk_widget_set_no_show_all (priv->mail_header_view, TRUE);
1404 gtk_widget_queue_resize (GTK_WIDGET(self));
1405 gtk_widget_queue_draw (GTK_WIDGET(self));
1407 if (priv->hadj != NULL)
1408 priv->hadj->value = 0.0;
1409 if (priv->vadj != NULL)
1410 priv->vadj->value = 0.0;
1412 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1414 g_signal_emit_by_name (G_OBJECT (html_vadj), "changed");
1416 /* This is a hack to force reallocation of scroll after drawing all the stuff. This
1417 * makes the html view get the proper and expected size and prevent being able to scroll
1418 * the buffer when it shouldn't be scrollable */
1419 g_object_ref (self);
1420 g_timeout_add (250, (GSourceFunc) idle_readjust_scroll, self);
1425 get_message (ModestMsgView *self)
1429 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), NULL);
1431 msg = MODEST_MSG_VIEW_GET_PRIVATE(self)->msg;
1440 modest_msg_view_get_message_is_empty (ModestMsgView *self)
1442 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1444 return modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->body_view));
1447 /* TNY MSG IMPLEMENTATION */
1450 tny_msg_view_init (gpointer g, gpointer iface_data)
1452 TnyMsgViewIface *klass = (TnyMsgViewIface *)g;
1454 klass->get_msg_func = modest_msg_view_get_msg;
1455 klass->set_msg_func = modest_msg_view_set_msg;
1456 klass->set_unavailable_func = modest_msg_view_set_unavailable;
1457 klass->clear_func = modest_msg_view_clear;
1458 klass->create_mime_part_view_for_func = modest_msg_view_create_mime_part_view_for;
1459 klass->create_new_inline_viewer_func = modest_msg_view_create_new_inline_viewer;
1465 modest_msg_view_get_msg (TnyMsgView *self)
1467 return MODEST_MSG_VIEW_GET_CLASS (self)->get_msg_func (self);
1471 modest_msg_view_get_msg_default (TnyMsgView *self)
1473 return TNY_MSG (tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (self)));
1477 modest_msg_view_set_msg (TnyMsgView *self, TnyMsg *msg)
1479 MODEST_MSG_VIEW_GET_CLASS (self)->set_msg_func (self, msg);
1483 modest_msg_view_set_msg_default (TnyMsgView *self, TnyMsg *msg)
1486 tny_mime_part_view_set_part (TNY_MIME_PART_VIEW (self), TNY_MIME_PART (msg));
1492 modest_msg_view_set_unavailable (TnyMsgView *self)
1494 MODEST_MSG_VIEW_GET_CLASS (self)->set_unavailable_func (self);
1498 modest_msg_view_set_unavailable_default (TnyMsgView *self)
1500 tny_msg_view_clear (self);
1506 modest_msg_view_clear (TnyMsgView *self)
1508 MODEST_MSG_VIEW_GET_CLASS (self)->clear_func (self);
1512 modest_msg_view_clear_default (TnyMsgView *self)
1514 set_message (MODEST_MSG_VIEW (self), NULL);
1517 static TnyMimePartView*
1518 modest_msg_view_create_mime_part_view_for (TnyMsgView *self, TnyMimePart *part)
1520 return MODEST_MSG_VIEW_GET_CLASS (self)->create_mime_part_view_for_func (self, part);
1523 static TnyMimePartView*
1524 modest_msg_view_create_mime_part_view_for_default (TnyMsgView *self, TnyMimePart *part)
1526 g_warning ("modest_msg_view_create_mime_part_view_for_default is not implemented");
1531 modest_msg_view_create_new_inline_viewer (TnyMsgView *self)
1533 return MODEST_MSG_VIEW_GET_CLASS (self)->create_new_inline_viewer_func (self);
1537 modest_msg_view_create_new_inline_viewer_default (TnyMsgView *self)
1539 g_warning ("modest_msg_view_create_new_inline_viewer_default is not implemented");
1544 /* TNY MIME PART IMPLEMENTATION */
1547 tny_mime_part_view_init (gpointer g, gpointer iface_data)
1549 TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
1551 klass->get_part_func = modest_msg_view_mp_get_part;
1552 klass->set_part_func = modest_msg_view_mp_set_part;
1553 klass->clear_func = modest_msg_view_mp_clear;
1559 modest_msg_view_mp_get_part (TnyMimePartView *self)
1561 return MODEST_MSG_VIEW_GET_CLASS (self)->get_part_func (self);
1566 modest_msg_view_mp_get_part_default (TnyMimePartView *self)
1568 return TNY_MIME_PART (get_message (MODEST_MSG_VIEW (self)));
1572 modest_msg_view_mp_set_part (TnyMimePartView *self,
1575 MODEST_MSG_VIEW_GET_CLASS (self)->set_part_func (self, part);
1579 modest_msg_view_mp_set_part_default (TnyMimePartView *self,
1582 g_return_if_fail ((part == NULL) || TNY_IS_MSG (part));
1584 set_message (MODEST_MSG_VIEW (self), TNY_MSG (part));
1588 modest_msg_view_mp_clear (TnyMimePartView *self)
1590 tny_msg_view_clear (TNY_MSG_VIEW (self));
1593 /* MODEST ZOOMABLE IMPLEMENTATION */
1595 modest_zoomable_init (gpointer g, gpointer iface_data)
1597 ModestZoomableIface *klass = (ModestZoomableIface *)g;
1599 klass->get_zoom_func = modest_msg_view_get_zoom;
1600 klass->set_zoom_func = modest_msg_view_set_zoom;
1601 klass->zoom_minus_func = modest_msg_view_zoom_minus;
1602 klass->zoom_plus_func = modest_msg_view_zoom_plus;
1608 modest_msg_view_get_zoom (ModestZoomable *self)
1610 return MODEST_MSG_VIEW_GET_CLASS (self)->get_zoom_func (self);
1614 modest_msg_view_get_zoom_default (ModestZoomable *self)
1616 return get_zoom (MODEST_MSG_VIEW (self));
1620 modest_msg_view_set_zoom (ModestZoomable *self, gdouble value)
1622 MODEST_MSG_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
1626 modest_msg_view_set_zoom_default (ModestZoomable *self, gdouble value)
1628 set_zoom (MODEST_MSG_VIEW (self), value);
1632 modest_msg_view_zoom_minus (ModestZoomable *self)
1634 return MODEST_MSG_VIEW_GET_CLASS (self)->zoom_minus_func (self);
1638 modest_msg_view_zoom_minus_default (ModestZoomable *self)
1640 /* operation not supported in ModestMsgView */
1645 modest_msg_view_zoom_plus (ModestZoomable *self)
1647 return MODEST_MSG_VIEW_GET_CLASS (self)->zoom_plus_func (self);
1651 modest_msg_view_zoom_plus_default (ModestZoomable *self)
1653 /* operation not supported in ModestMsgView */
1657 /* INCREMENTAL SEARCH IMPLEMENTATION */
1660 modest_msg_view_search (ModestMsgView *self, const gchar *search)
1662 ModestMsgViewPrivate *priv;
1664 GtkAdjustment *vadj, *tmp_vadj;
1667 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), FALSE);
1669 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1670 vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (priv->body_view));
1671 g_object_ref (vadj);
1672 tmp_vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, vadj->lower, vadj->upper, vadj->step_increment, 32.0, 32.0));
1673 gtk_layout_set_vadjustment (GTK_LAYOUT (priv->body_view), tmp_vadj);
1674 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->body_view),
1679 gdouble offset_top, offset_bottom;
1681 modest_isearch_view_get_selection_area (MODEST_ISEARCH_VIEW (priv->body_view), &x, &y, &w, &h);
1682 offset_top = (gdouble) (priv->headers_box->requisition.height + y);
1683 offset_bottom = (gdouble) (priv->headers_box->requisition.height + y + h);
1684 adj = GTK_ADJUSTMENT (priv->vadj);
1685 if (offset_top < adj->value)
1686 gtk_adjustment_set_value (adj, offset_top + adj->page_increment - adj->page_size);
1687 else if (offset_bottom > adj->value + adj->page_increment)
1688 gtk_adjustment_set_value (adj, offset_bottom - adj->page_increment);
1691 y_offset = tmp_vadj->value;
1692 gtk_layout_set_vadjustment (GTK_LAYOUT (priv->body_view), vadj);
1693 g_object_unref (vadj);
1699 modest_msg_view_search_next (ModestMsgView *self)
1701 ModestMsgViewPrivate *priv;
1704 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), FALSE);
1706 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1707 result = modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->body_view));
1711 gdouble offset_top, offset_bottom;
1713 modest_isearch_view_get_selection_area (MODEST_ISEARCH_VIEW (priv->body_view), &x, &y, &w, &h);
1714 offset_top = (gdouble) (priv->headers_box->requisition.height + y);
1715 offset_bottom = (gdouble) (priv->headers_box->requisition.height + y + h);
1716 adj = GTK_ADJUSTMENT (priv->vadj);
1717 if (offset_top < adj->value)
1718 gtk_adjustment_set_value (adj, offset_top + adj->page_increment - adj->page_size);
1719 else if (offset_bottom > adj->value + adj->page_increment)
1720 gtk_adjustment_set_value (adj, offset_bottom - adj->page_increment);
1725 /* ZOOM IMPLEMENTATION */
1728 set_zoom (ModestMsgView *self, gdouble zoom)
1730 ModestMsgViewPrivate *priv;
1732 g_return_if_fail (MODEST_IS_MSG_VIEW (self));
1733 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1735 modest_zoomable_set_zoom (MODEST_ZOOMABLE(priv->body_view), zoom);
1737 gtk_widget_queue_resize (priv->body_view);
1741 get_zoom (ModestMsgView *self)
1743 ModestMsgViewPrivate *priv;
1745 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), 1.0);
1746 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1748 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->body_view));
1752 modest_msg_view_get_priority (ModestMsgView *self)
1754 ModestMsgViewPrivate *priv;
1756 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), 0);
1758 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1760 return priv->priority_flags;
1764 modest_msg_view_set_priority (ModestMsgView *self, TnyHeaderFlags flags)
1766 ModestMsgViewPrivate *priv;
1768 g_return_if_fail (MODEST_IS_MSG_VIEW (self));
1770 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1772 priv->priority_flags = flags & (TNY_HEADER_FLAG_HIGH_PRIORITY);
1774 modest_mail_header_view_set_priority (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), flags);
1778 modest_msg_view_get_selected_attachments (ModestMsgView *self)
1780 ModestMsgViewPrivate *priv;
1782 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), NULL);
1783 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1785 return modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1790 modest_msg_view_get_attachments (ModestMsgView *self)
1792 ModestMsgViewPrivate *priv;
1794 g_return_val_if_fail (MODEST_IS_MSG_VIEW (self), NULL);
1795 priv = MODEST_MSG_VIEW_GET_PRIVATE (self);
1797 return modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1802 modest_msg_view_grab_focus (ModestMsgView *view)
1804 ModestMsgViewPrivate *priv = NULL;
1806 g_return_if_fail (MODEST_IS_MSG_VIEW (view));
1807 priv = MODEST_MSG_VIEW_GET_PRIVATE (view);
1809 gtk_widget_grab_focus (priv->body_view);
1813 modest_msg_view_remove_attachment (ModestMsgView *view, TnyMimePart *attachment)
1815 ModestMsgViewPrivate *priv;
1817 g_return_if_fail (MODEST_IS_MSG_VIEW (view));
1818 g_return_if_fail (TNY_IS_MIME_PART (attachment));
1819 priv = MODEST_MSG_VIEW_GET_PRIVATE (view);
1821 modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1827 idle_readjust_scroll (ModestMsgView *view)
1829 if (GTK_WIDGET_DRAWABLE (view)) {
1830 ModestMsgViewPrivate *priv = MODEST_MSG_VIEW_GET_PRIVATE (view);
1831 GtkAdjustment *html_vadj;
1832 html_vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->html_scroll));
1833 html_vadj->page_size = html_vadj->upper;
1834 gtk_adjustment_changed (html_vadj);
1835 gtk_widget_queue_resize (GTK_WIDGET (view));
1836 gtk_widget_queue_draw (GTK_WIDGET (view));
1838 /* Just another hack for making readjust really work. This forces an update
1839 * of the scroll, and then, make the scroll really update properly the
1840 * the size and not corrupt scrollable area */
1841 gtk_adjustment_set_value (priv->vadj, 1.0);
1842 gtk_adjustment_set_value (priv->vadj, 0.0);
1844 g_object_unref (G_OBJECT (view));