Some default settings for webkit widget.
[modest] / src / widgets / modest-webkit-mime-part-view.c
1 /* Copyright (c) 2006, 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #include <config.h>
31 #include <widgets/modest-webkit-mime-part-view.h>
32 #include <string.h>
33 #include <webkit/webkit.h>
34 #include <tny-stream.h>
35 #include <tny-mime-part-view.h>
36 #include "modest-tny-mime-part.h"
37 #include <modest-stream-text-to-html.h>
38 #include <modest-text-utils.h>
39 #include <modest-conf.h>
40 #include <modest-runtime.h>
41 #include <widgets/modest-mime-part-view.h>
42 #include <widgets/modest-zoomable.h>
43 #include <libgnomevfs/gnome-vfs.h>
44 #include <gdk/gdkkeysyms.h>
45 #include <modest-ui-constants.h>
46 #include <modest-tny-stream-webkit.h>
47
48 /* gobject structure methods */
49 static void    modest_webkit_mime_part_view_class_init (ModestWebkitMimePartViewClass *klass);
50 static void    tny_mime_part_view_init                  (gpointer g, gpointer iface_data);
51 static void    modest_mime_part_view_init               (gpointer g, gpointer iface_data);
52 static void    modest_zoomable_init                     (gpointer g, gpointer iface_data);
53 static void    modest_isearch_view_init                 (gpointer g, gpointer iface_data);
54 static void    modest_webkit_mime_part_view_init       (ModestWebkitMimePartView *self);
55 static void    modest_webkit_mime_part_view_finalize   (GObject *self);
56 static void    modest_webkit_mime_part_view_dispose    (GObject *self);
57
58 /* Webkit signal handlers */
59 static void on_resource_request_starting (WebKitWebView *webview,
60                                           WebKitWebFrame *frame,
61                                           WebKitWebResource *resource,
62                                           WebKitNetworkRequest *request,
63                                           WebKitNetworkResponse *response,
64                                           gpointer userdata);
65 static void      on_notify_style  (GObject *obj, GParamSpec *spec, gpointer userdata);
66 static gboolean  update_style     (ModestWebkitMimePartView *self);
67 /* TnyMimePartView implementation */
68 static void modest_webkit_mime_part_view_clear (TnyMimePartView *self);
69 static void modest_webkit_mime_part_view_clear_default (TnyMimePartView *self);
70 static void modest_webkit_mime_part_view_set_part (TnyMimePartView *self, TnyMimePart *part);
71 static void modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self, TnyMimePart *part);
72 static TnyMimePart* modest_webkit_mime_part_view_get_part (TnyMimePartView *self);
73 static TnyMimePart* modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self);
74 /* ModestMimePartView implementation */
75 static gboolean modest_webkit_mime_part_view_is_empty (ModestMimePartView *self);
76 static gboolean modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self);
77 static gboolean modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self);
78 static gboolean modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self);
79 static void     modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images);
80 static void     modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images);
81 static gboolean modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self);
82 static gboolean modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self);
83 /* ModestZoomable implementation */
84 static gdouble modest_webkit_mime_part_view_get_zoom (ModestZoomable *self);
85 static void modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value);
86 static gboolean modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self);
87 static gboolean modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self);
88 static gdouble modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self);
89 static void modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value);
90 static gboolean modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self);
91 static gboolean modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self);
92 /* ModestISearchView implementation */
93 static gboolean modest_webkit_mime_part_view_search                    (ModestISearchView *self, const gchar *string);
94 static gboolean modest_webkit_mime_part_view_search_next               (ModestISearchView *self);
95 static gboolean modest_webkit_mime_part_view_get_selection_area        (ModestISearchView *self, gint *x, gint *y, 
96                                                                          gint *width, gint *height);
97 static gboolean modest_webkit_mime_part_view_search_default            (ModestISearchView *self, const gchar *string);
98 static gboolean modest_webkit_mime_part_view_search_next_default       (ModestISearchView *self);
99 static gboolean modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
100                                                                           gint *width, gint *height);
101
102
103 /* internal api */
104 static TnyMimePart  *get_part   (ModestWebkitMimePartView *self);
105 static void          set_html_part   (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding);
106 static void          set_text_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
107 static void          set_empty_part  (ModestWebkitMimePartView *self);
108 static void          set_part   (ModestWebkitMimePartView *self, TnyMimePart *part);
109 static gboolean      is_empty   (ModestWebkitMimePartView *self);
110 static gboolean      get_view_images   (ModestWebkitMimePartView *self);
111 static void          set_view_images   (ModestWebkitMimePartView *self, gboolean view_images);
112 static gboolean      has_external_images   (ModestWebkitMimePartView *self);
113 static void          set_zoom   (ModestWebkitMimePartView *self, gdouble zoom);
114 static gdouble       get_zoom   (ModestWebkitMimePartView *self);
115 static gboolean      search             (ModestWebkitMimePartView *self, const gchar *string);
116 static gboolean      search_next        (ModestWebkitMimePartView *self);
117 static gboolean      get_selection_area (ModestWebkitMimePartView *self, gint *x, gint *y,
118                                          gint *width, gint *height);
119
120 typedef struct _ModestWebkitMimePartViewPrivate ModestWebkitMimePartViewPrivate;
121 struct _ModestWebkitMimePartViewPrivate {
122         TnyMimePart *part;
123         gdouble current_zoom;
124         gboolean view_images;
125         gboolean has_external_images;
126         GSList *sighandlers;
127 };
128
129 #define MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
130                                                                                        MODEST_TYPE_WEBKIT_MIME_PART_VIEW, \
131                                                                                        ModestWebkitMimePartViewPrivate))
132
133 enum {
134         STOP_STREAMS_SIGNAL,
135         LIMIT_ERROR_SIGNAL,
136         LAST_SIGNAL
137 };
138
139 static WebKitWebViewClass *parent_class = NULL;
140
141 static guint signals[LAST_SIGNAL] = {0};
142
143 GtkWidget *
144 modest_webkit_mime_part_view_new ()
145 {
146         return g_object_new (MODEST_TYPE_WEBKIT_MIME_PART_VIEW, NULL);
147 }
148
149 /* GOBJECT IMPLEMENTATION */
150 GType
151 modest_webkit_mime_part_view_get_type (void)
152 {
153         static GType my_type = 0;
154         if (!my_type) {
155                 static const GTypeInfo my_info = {
156                         sizeof(ModestWebkitMimePartViewClass),
157                         NULL,           /* base init */
158                         NULL,           /* base finalize */
159                         (GClassInitFunc) modest_webkit_mime_part_view_class_init,
160                         NULL,           /* class finalize */
161                         NULL,           /* class data */
162                         sizeof(ModestWebkitMimePartView),
163                         1,              /* n_preallocs */
164                         (GInstanceInitFunc) modest_webkit_mime_part_view_init,
165                         NULL
166                 };
167
168                 static const GInterfaceInfo tny_mime_part_view_info = 
169                 {
170                   (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
171                   NULL,         /* interface_finalize */
172                   NULL          /* interface_data */
173                 };
174
175                 static const GInterfaceInfo modest_mime_part_view_info = 
176                 {
177                   (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */
178                   NULL,         /* interface_finalize */
179                   NULL          /* interface_data */
180                 };
181
182                 static const GInterfaceInfo modest_zoomable_info = 
183                 {
184                   (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
185                   NULL,         /* interface_finalize */
186                   NULL          /* interface_data */
187                 };
188
189                 static const GInterfaceInfo modest_isearch_view_info = 
190                 {
191                   (GInterfaceInitFunc) modest_isearch_view_init, /* interface_init */
192                   NULL,         /* interface_finalize */
193                   NULL          /* interface_data */
194                 };
195
196                 my_type = g_type_register_static (WEBKIT_TYPE_WEB_VIEW,
197                                                   "ModestWebkitMimePartView",
198                                                   &my_info, 0);
199
200                 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, 
201                         &tny_mime_part_view_info);
202
203                 g_type_add_interface_static (my_type, MODEST_TYPE_MIME_PART_VIEW, 
204                         &modest_mime_part_view_info);
205
206                 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE, 
207                         &modest_zoomable_info);
208                 g_type_add_interface_static (my_type, MODEST_TYPE_ISEARCH_VIEW, 
209                         &modest_isearch_view_info);
210         }
211         return my_type;
212 }
213
214 static void
215 modest_webkit_mime_part_view_class_init (ModestWebkitMimePartViewClass *klass)
216 {
217         GObjectClass *gobject_class;
218         GtkBindingSet *binding_set;
219
220         gobject_class = (GObjectClass*) klass;
221
222         parent_class            = g_type_class_peek_parent (klass);
223         gobject_class->dispose = modest_webkit_mime_part_view_dispose;
224         gobject_class->finalize = modest_webkit_mime_part_view_finalize;
225
226         klass->get_part_func = modest_webkit_mime_part_view_get_part_default;
227         klass->set_part_func = modest_webkit_mime_part_view_set_part_default;
228         klass->clear_func = modest_webkit_mime_part_view_clear_default;
229         klass->is_empty_func = modest_webkit_mime_part_view_is_empty_default;
230         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images_default;
231         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images_default;
232         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images_default;
233         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom_default;
234         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom_default;
235         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus_default;
236         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus_default;
237         klass->search_func = modest_webkit_mime_part_view_search_default;
238         klass->search_next_func = modest_webkit_mime_part_view_search_next_default;
239         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area_default;
240
241         binding_set = gtk_binding_set_by_class (klass);
242         gtk_binding_entry_skip (binding_set, GDK_Down, 0);
243         gtk_binding_entry_skip (binding_set, GDK_Up, 0);
244         gtk_binding_entry_skip (binding_set, GDK_KP_Up, 0);
245         gtk_binding_entry_skip (binding_set, GDK_KP_Down, 0);
246         gtk_binding_entry_skip (binding_set, GDK_Page_Down, 0);
247         gtk_binding_entry_skip (binding_set, GDK_Page_Up, 0);
248         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Up, 0);
249         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Down, 0);
250         gtk_binding_entry_skip (binding_set, GDK_Home, 0);
251         gtk_binding_entry_skip (binding_set, GDK_End, 0);
252         gtk_binding_entry_skip (binding_set, GDK_KP_Home, 0);
253         gtk_binding_entry_skip (binding_set, GDK_KP_End, 0);
254
255         g_type_class_add_private (gobject_class, sizeof(ModestWebkitMimePartViewPrivate));
256
257         signals[STOP_STREAMS_SIGNAL] = 
258                 g_signal_new ("stop-streams",
259                               G_TYPE_FROM_CLASS (gobject_class),
260                               G_SIGNAL_RUN_FIRST,
261                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,stop_streams),
262                               NULL, NULL,
263                               g_cclosure_marshal_VOID__VOID,
264                               G_TYPE_NONE, 0);
265
266         signals[LIMIT_ERROR_SIGNAL] = 
267                 g_signal_new ("limit-error",
268                               G_TYPE_FROM_CLASS (gobject_class),
269                               G_SIGNAL_RUN_FIRST,
270                               G_STRUCT_OFFSET (ModestWebkitMimePartViewClass,limit_error),
271                               NULL, NULL,
272                               g_cclosure_marshal_VOID__VOID,
273                               G_TYPE_NONE, 0);
274
275 }
276
277 static void
278 modest_webkit_mime_part_view_init (ModestWebkitMimePartView *self)
279 {
280         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
281         GdkColor base;
282         GdkColor text;
283         WebKitWebSettings *settings;
284
285         gdk_color_parse ("#fff", &base);
286         gdk_color_parse ("#000", &text);
287         gtk_widget_modify_base (GTK_WIDGET (self), GTK_STATE_NORMAL, &base);
288         gtk_widget_modify_text (GTK_WIDGET (self), GTK_STATE_NORMAL, &text);
289
290         priv->sighandlers = NULL;
291
292         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
293                                                        G_OBJECT(self), "notify::style",
294                                                        G_CALLBACK (on_notify_style), (gpointer) self);
295         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
296                                                        G_OBJECT (self), "resource-request-starting",
297                                                        G_CALLBACK (on_resource_request_starting), (gpointer) self);
298
299         priv->part = NULL;
300         priv->current_zoom = 1.0;
301         priv->view_images = FALSE;
302         priv->has_external_images = FALSE;
303
304         settings = webkit_web_settings_new ();
305         g_object_set (G_OBJECT (settings),
306                       "auto-load-images", FALSE,
307                       "enable-html5-database", FALSE,
308                       "enable-html5-local-storage", FALSE, 
309                       "enable-offline-web-application-cache", FALSE,
310                       "enable-plugins", FALSE,
311                       "enable-private-browsing", TRUE,
312                       "enable-scripts", FALSE,
313                       NULL);
314         webkit_web_view_set_settings (WEBKIT_WEB_VIEW (self), settings);
315         g_object_unref (settings);
316         g_object_set (G_OBJECT (self), 
317                       "editable", FALSE,
318                       NULL);
319 }
320
321 static void
322 modest_webkit_mime_part_view_finalize (GObject *obj)
323 {
324         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
325
326         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
327         priv->sighandlers = NULL;
328
329         G_OBJECT_CLASS (parent_class)->finalize (obj);
330 }
331
332 static void
333 modest_webkit_mime_part_view_dispose (GObject *obj)
334 {
335         ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (obj);
336
337         g_signal_emit (G_OBJECT (obj), signals[STOP_STREAMS_SIGNAL], 0);
338
339         if (priv->part) {
340                 g_object_unref (priv->part);
341                 priv->part = NULL;
342         }
343
344         G_OBJECT_CLASS (parent_class)->dispose (obj);
345 }
346
347 /* WEBKIT SIGNALS HANDLERS */
348
349 static void
350 on_resource_request_starting (WebKitWebView *webview,
351                               WebKitWebFrame *frame,
352                               WebKitWebResource *resource,
353                               WebKitNetworkRequest *request,
354                               WebKitNetworkResponse *response,
355                               gpointer userdata)
356 {
357         ModestWebkitMimePartView *self = (ModestWebkitMimePartView *) userdata;
358         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
359
360         if (g_str_has_prefix (webkit_network_request_get_uri (request), "http:")) {
361                 ModestWebkitMimePartViewPrivate *priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
362
363                 if (!priv->view_images)
364                         priv->has_external_images = TRUE;
365         }
366
367         webkit_network_request_set_uri (request, "about:blank");
368 }
369
370 static void 
371 on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata)
372 {
373         if (strcmp ("style", spec->name) == 0) {
374                 g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) update_style, 
375                                  g_object_ref (obj), g_object_unref);
376                 gtk_widget_queue_draw (GTK_WIDGET (obj));
377         }
378 }
379
380 gboolean
381 same_color (GdkColor *a, GdkColor *b)
382 {
383         return ((a->red == b->red) && 
384                 (a->green == b->green) && 
385                 (a->blue == b->blue));
386 }
387
388 static gboolean
389 update_style (ModestWebkitMimePartView *self)
390 {
391         GdkColor base;
392         GdkColor text;
393         GtkRcStyle *rc_style;
394
395         gdk_threads_enter ();
396
397         if (GTK_WIDGET_VISIBLE (self)) {
398                 rc_style = gtk_widget_get_modifier_style (GTK_WIDGET (self));
399
400                 gdk_color_parse ("#fff", &base);
401                 gdk_color_parse ("#000", &text);
402
403                 if (!same_color (&(rc_style->base[GTK_STATE_NORMAL]), &base) &&
404                     !same_color (&(rc_style->text[GTK_STATE_NORMAL]), &text)) {
405
406                         rc_style->base[GTK_STATE_NORMAL] = base;
407                         rc_style->text[GTK_STATE_NORMAL] = text;
408                         gtk_widget_modify_style (GTK_WIDGET (self), rc_style);
409                 }
410         }
411
412         gdk_threads_leave ();
413
414         return FALSE;
415 }
416
417
418 /* INTERNAL API */
419 static void
420 decode_to_stream_cb (TnyMimePart *self,
421                      gboolean cancelled,
422                      TnyStream *stream,
423                      GError *err,
424                      gpointer user_data)
425 {
426         ModestWebkitMimePartView *view = (ModestWebkitMimePartView *) user_data;
427
428         if (MODEST_IS_STREAM_TEXT_TO_HTML (stream)) {
429                 if (tny_stream_write (stream, "\n", 1) == -1) {
430                         g_warning ("failed to write CR in %s", __FUNCTION__);
431                 }
432                 if (modest_stream_text_to_html_limit_reached (MODEST_STREAM_TEXT_TO_HTML (stream))) {
433                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
434                 }
435                 tny_stream_reset (stream);
436         } else {
437                 if (modest_tny_stream_webkit_limit_reached (MODEST_TNY_STREAM_WEBKIT (stream))) {
438                         g_signal_emit (G_OBJECT (view), signals[LIMIT_ERROR_SIGNAL], 0);
439                 }
440         }
441         tny_stream_close (stream);
442 }
443
444 static void
445 set_html_part (ModestWebkitMimePartView *self, TnyMimePart *part, const gchar *encoding)
446 {
447         TnyStream *tny_stream;
448
449         g_return_if_fail (self);
450         g_return_if_fail (part);
451
452         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
453
454         tny_stream     = TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", encoding));
455         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
456         tny_stream_reset (tny_stream);
457
458         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
459                                               tny_stream, decode_to_stream_cb,
460                                               NULL, self);
461         g_object_unref (tny_stream);
462 }
463
464 static void
465 set_text_part (ModestWebkitMimePartView *self, TnyMimePart *part)
466 {
467         TnyStream* text_to_html_stream, *tny_stream;
468
469         g_return_if_fail (self);
470         g_return_if_fail (part);
471
472         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
473
474         tny_stream =  TNY_STREAM(modest_tny_stream_webkit_new (WEBKIT_WEB_VIEW (self), "text/html", "utf-8"));
475         modest_tny_stream_webkit_set_max_size (MODEST_TNY_STREAM_WEBKIT (tny_stream), 128*1024);
476         text_to_html_stream = TNY_STREAM (modest_stream_text_to_html_new (tny_stream));
477         modest_stream_text_to_html_set_linkify_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
478                                                       64*1024);
479         modest_stream_text_to_html_set_full_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
480                                                    128*1024);
481         modest_stream_text_to_html_set_line_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream),
482                                                    1024);
483
484         tny_mime_part_decode_to_stream_async (TNY_MIME_PART (part),
485                                               text_to_html_stream, decode_to_stream_cb,
486                                               NULL, self);
487
488         g_object_unref (G_OBJECT(text_to_html_stream));
489         g_object_unref (G_OBJECT(tny_stream));
490 }
491
492 static void
493 set_empty_part (ModestWebkitMimePartView *self)
494 {
495         g_return_if_fail (self);
496
497         g_signal_emit (G_OBJECT (self), signals[STOP_STREAMS_SIGNAL], 0);
498         webkit_web_view_load_string (WEBKIT_WEB_VIEW (self), "", "text/plain", "utf-8", NULL);
499 }
500
501 static void
502 set_part (ModestWebkitMimePartView *self, TnyMimePart *part)
503 {
504         ModestWebkitMimePartViewPrivate *priv;
505         gchar *header_content_type, *header_content_type_lower;
506         const gchar *tmp;
507         gchar *charset = NULL;
508
509         g_return_if_fail (self);
510         
511         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self);
512         priv->has_external_images = FALSE;
513
514         if (part != priv->part) {
515                 if (priv->part)
516                         g_object_unref (G_OBJECT(priv->part));
517                 if (part)
518                         g_object_ref   (G_OBJECT(part));
519                 priv->part = part;
520         }
521         
522         if (!part) {
523                 set_empty_part (self);
524                 return;
525         }
526
527         header_content_type = modest_tny_mime_part_get_header_value (part, "Content-Type");
528         if (header_content_type) {
529                 header_content_type = g_strstrip (header_content_type);
530                 header_content_type_lower = g_ascii_strdown (header_content_type, -1);
531         } else {
532                 header_content_type_lower = NULL;
533         }
534
535         if (header_content_type_lower) {
536                 tmp = strstr (header_content_type_lower, "charset=");
537                 if (tmp) {
538                         const gchar *tmp2;
539                         tmp = tmp + strlen ("charset=");
540                         
541                         tmp2 = strstr (tmp, ";");
542                         if (tmp2) {
543                                 charset = g_strndup (tmp, tmp2-tmp);
544                         } else {
545                                 charset = g_strdup (tmp);
546                         }
547                 }
548         }
549
550         if (tny_mime_part_content_type_is (part, "text/html")) {
551                 set_html_part (self, part, charset);
552         } else {
553                 if (tny_mime_part_content_type_is (part, "message/rfc822")) {
554                         if (header_content_type) {
555                                 if (g_str_has_prefix (header_content_type_lower, "text/html"))
556                                         set_html_part (self, part, charset);
557                                 else 
558                                         set_text_part (self, part);
559
560                         } else {
561                                 set_text_part (self, part);
562                         }
563                 } else {
564                         set_text_part (self, part);
565                 }
566         }
567         g_free (header_content_type_lower);
568         g_free (header_content_type);
569
570 }
571
572 static TnyMimePart*
573 get_part (ModestWebkitMimePartView *self)
574 {
575         TnyMimePart *part;
576
577         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), NULL);
578
579         part = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE(self)->part;
580
581         if (part)
582                 g_object_ref (part);
583         
584         return part;
585 }
586
587 static gboolean      
588 is_empty   (ModestWebkitMimePartView *self)
589 {
590         return FALSE;
591 }
592
593 static gboolean      
594 get_view_images   (ModestWebkitMimePartView *self)
595 {
596         ModestWebkitMimePartViewPrivate *priv;
597
598         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
599
600         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
601         return priv->view_images;
602 }
603
604 static void
605 set_view_images   (ModestWebkitMimePartView *self, gboolean view_images)
606 {
607         ModestWebkitMimePartViewPrivate *priv;
608
609         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
610
611         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
612         priv->view_images = view_images;
613 }
614
615 static gboolean      
616 has_external_images   (ModestWebkitMimePartView *self)
617 {
618         ModestWebkitMimePartViewPrivate *priv;
619
620         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), FALSE);
621
622         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
623         return priv->has_external_images;
624 }
625
626 static void
627 set_zoom (ModestWebkitMimePartView *self, gdouble zoom)
628 {
629         ModestWebkitMimePartViewPrivate *priv;
630
631         g_return_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self));
632
633         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
634         priv->current_zoom = zoom;
635
636         gtk_widget_queue_resize (GTK_WIDGET (self));
637 }
638
639 static gdouble
640 get_zoom (ModestWebkitMimePartView *self)
641 {
642         ModestWebkitMimePartViewPrivate *priv;
643
644         g_return_val_if_fail (MODEST_IS_WEBKIT_MIME_PART_VIEW (self), 1.0);
645
646         priv = MODEST_WEBKIT_MIME_PART_VIEW_GET_PRIVATE (self);
647
648         return priv->current_zoom;
649 }
650
651 static gboolean
652 search (ModestWebkitMimePartView *self, 
653         const gchar *string)
654 {
655         return FALSE;
656 }
657
658 static gboolean
659 search_next (ModestWebkitMimePartView *self)
660 {
661         return FALSE;
662 }
663
664 static gboolean
665 get_selection_area (ModestWebkitMimePartView *self, 
666                     gint *x, gint *y,
667                     gint *width, gint *height)
668 {
669         return FALSE;
670 }
671
672
673 /* TNY MIME PART IMPLEMENTATION */
674
675 static void
676 tny_mime_part_view_init (gpointer g, gpointer iface_data)
677 {
678         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
679
680         klass->get_part = modest_webkit_mime_part_view_get_part;
681         klass->set_part = modest_webkit_mime_part_view_set_part;
682         klass->clear = modest_webkit_mime_part_view_clear;
683
684         return;
685 }
686
687 static TnyMimePart* 
688 modest_webkit_mime_part_view_get_part (TnyMimePartView *self)
689 {
690         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
691 }
692
693
694 static TnyMimePart* 
695 modest_webkit_mime_part_view_get_part_default (TnyMimePartView *self)
696 {
697         return TNY_MIME_PART (get_part (MODEST_WEBKIT_MIME_PART_VIEW (self)));
698 }
699
700 static void
701 modest_webkit_mime_part_view_set_part (TnyMimePartView *self,
702                                         TnyMimePart *part)
703 {
704         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
705 }
706
707 static void
708 modest_webkit_mime_part_view_set_part_default (TnyMimePartView *self,
709                                                 TnyMimePart *part)
710 {
711         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
712
713         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), part);
714 }
715
716 static void
717 modest_webkit_mime_part_view_clear (TnyMimePartView *self)
718 {
719         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
720 }
721
722 static void
723 modest_webkit_mime_part_view_clear_default (TnyMimePartView *self)
724 {
725         set_part (MODEST_WEBKIT_MIME_PART_VIEW (self), NULL);
726 }
727
728 /* MODEST MIME PART VIEW IMPLEMENTATION */
729
730 static void
731 modest_mime_part_view_init (gpointer g, gpointer iface_data)
732 {
733         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
734
735         klass->is_empty_func = modest_webkit_mime_part_view_is_empty;
736         klass->get_view_images_func = modest_webkit_mime_part_view_get_view_images;
737         klass->set_view_images_func = modest_webkit_mime_part_view_set_view_images;
738         klass->has_external_images_func = modest_webkit_mime_part_view_has_external_images;
739
740         return;
741 }
742
743 static gboolean
744 modest_webkit_mime_part_view_is_empty (ModestMimePartView *self)
745 {
746         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
747 }
748
749 static gboolean
750 modest_webkit_mime_part_view_get_view_images (ModestMimePartView *self)
751 {
752         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_view_images_func (self);
753 }
754
755 static void
756 modest_webkit_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images)
757 {
758         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_view_images_func (self, view_images);
759 }
760
761 static gboolean
762 modest_webkit_mime_part_view_has_external_images (ModestMimePartView *self)
763 {
764         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->has_external_images_func (self);
765 }
766
767 static gboolean
768 modest_webkit_mime_part_view_is_empty_default (ModestMimePartView *self)
769 {
770         return is_empty (MODEST_WEBKIT_MIME_PART_VIEW (self));
771 }
772
773 static gboolean
774 modest_webkit_mime_part_view_get_view_images_default (ModestMimePartView *self)
775 {
776         return get_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
777 }
778
779 static void
780 modest_webkit_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images)
781 {
782         set_view_images (MODEST_WEBKIT_MIME_PART_VIEW (self), view_images);
783 }
784
785 static gboolean
786 modest_webkit_mime_part_view_has_external_images_default (ModestMimePartView *self)
787 {
788         return has_external_images (MODEST_WEBKIT_MIME_PART_VIEW (self));
789 }
790
791
792 /* MODEST ZOOMABLE IMPLEMENTATION */
793 static void
794 modest_zoomable_init (gpointer g, gpointer iface_data)
795 {
796         ModestZoomableIface *klass = (ModestZoomableIface *)g;
797         
798         klass->get_zoom_func = modest_webkit_mime_part_view_get_zoom;
799         klass->set_zoom_func = modest_webkit_mime_part_view_set_zoom;
800         klass->zoom_minus_func = modest_webkit_mime_part_view_zoom_minus;
801         klass->zoom_plus_func = modest_webkit_mime_part_view_zoom_plus;
802
803         return;
804 }
805
806 static gdouble
807 modest_webkit_mime_part_view_get_zoom (ModestZoomable *self)
808 {
809         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
810 }
811
812 static gdouble
813 modest_webkit_mime_part_view_get_zoom_default (ModestZoomable *self)
814 {
815         return get_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self));
816 }
817
818 static void
819 modest_webkit_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
820 {
821         MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
822 }
823
824 static void
825 modest_webkit_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
826 {
827         set_zoom (MODEST_WEBKIT_MIME_PART_VIEW (self), value);
828 }
829
830 static gboolean
831 modest_webkit_mime_part_view_zoom_minus (ModestZoomable *self)
832 {
833         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
834 }
835
836 static gboolean
837 modest_webkit_mime_part_view_zoom_minus_default (ModestZoomable *self)
838 {
839         /* operation not supported in ModestWebkitMimePartView */
840         return FALSE;
841 }
842
843 static gboolean
844 modest_webkit_mime_part_view_zoom_plus (ModestZoomable *self)
845 {
846         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
847 }
848
849 static gboolean
850 modest_webkit_mime_part_view_zoom_plus_default (ModestZoomable *self)
851 {
852         /* operation not supported in ModestWebkitMimePartView */
853         return FALSE;
854 }
855
856 /* ISEARCH VIEW IMPLEMENTATION */
857 static void
858 modest_isearch_view_init (gpointer g, gpointer iface_data)
859 {
860         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
861         
862         klass->search_func = modest_webkit_mime_part_view_search;
863         klass->search_next_func = modest_webkit_mime_part_view_search_next;
864         klass->get_selection_area_func = modest_webkit_mime_part_view_get_selection_area;
865
866         return;
867 }
868
869 static gboolean 
870 modest_webkit_mime_part_view_search (ModestISearchView *self, const gchar *string)
871 {
872         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
873 }
874
875 static gboolean 
876 modest_webkit_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
877 {
878         return search (MODEST_WEBKIT_MIME_PART_VIEW (self), string);
879 }
880
881 static gboolean 
882 modest_webkit_mime_part_view_search_next(ModestISearchView *self)
883 {
884         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
885 }
886
887 static gboolean 
888 modest_webkit_mime_part_view_search_next_default (ModestISearchView *self)
889 {
890         return search_next (MODEST_WEBKIT_MIME_PART_VIEW (self));
891 }
892
893 static gboolean 
894 modest_webkit_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
895                                                   gint *width, gint *height)
896 {
897         return MODEST_WEBKIT_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
898 }
899
900 static gboolean 
901 modest_webkit_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
902                                                           gint *width, gint *height)
903 {
904         return get_selection_area (MODEST_WEBKIT_MIME_PART_VIEW (self), x, y, width, height);
905 }