* src/modest-marshal.list:
[modest] / src / widgets / modest-gtkhtml-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-gtkhtml-mime-part-view.h>
32 #include <string.h>
33 #include <gtkhtml/gtkhtml-stream.h>
34 #include <gtkhtml/gtkhtml-search.h>
35 #include <tny-stream.h>
36 #include <tny-mime-part-view.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 <widgets/modest-tny-stream-gtkhtml.h>
44 #include <libgnomevfs/gnome-vfs.h>
45
46 /* gobject structure methods */
47 static void    modest_gtkhtml_mime_part_view_class_init (ModestGtkhtmlMimePartViewClass *klass);
48 static void    tny_mime_part_view_init                  (gpointer g, gpointer iface_data);
49 static void    modest_mime_part_view_init               (gpointer g, gpointer iface_data);
50 static void    modest_zoomable_init                     (gpointer g, gpointer iface_data);
51 static void    modest_isearch_view_init                 (gpointer g, gpointer iface_data);
52 static void    modest_gtkhtml_mime_part_view_init       (ModestGtkhtmlMimePartView *self);
53 static void    modest_gtkhtml_mime_part_view_finalize   (GObject *self);
54 static void    modest_gtkhtml_mime_part_view_dispose    (GObject *self);
55
56 /* GtkHTML signal handlers */
57 static gboolean  on_link_clicked  (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self);
58 static gboolean  on_url           (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self);
59 static gboolean  on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream,
60                                    ModestGtkhtmlMimePartView *self);
61 /* TnyMimePartView implementation */
62 static void modest_gtkhtml_mime_part_view_clear (TnyMimePartView *self);
63 static void modest_gtkhtml_mime_part_view_clear_default (TnyMimePartView *self);
64 static void modest_gtkhtml_mime_part_view_set_part (TnyMimePartView *self, TnyMimePart *part);
65 static void modest_gtkhtml_mime_part_view_set_part_default (TnyMimePartView *self, TnyMimePart *part);
66 static TnyMimePart* modest_gtkhtml_mime_part_view_get_part (TnyMimePartView *self);
67 static TnyMimePart* modest_gtkhtml_mime_part_view_get_part_default (TnyMimePartView *self);
68 /* ModestMimePartView implementation */
69 static gboolean modest_gtkhtml_mime_part_view_is_empty (ModestMimePartView *self);
70 static gboolean modest_gtkhtml_mime_part_view_is_empty_default (ModestMimePartView *self);
71 static gboolean modest_gtkhtml_mime_part_view_get_view_images (ModestMimePartView *self);
72 static gboolean modest_gtkhtml_mime_part_view_get_view_images_default (ModestMimePartView *self);
73 static void     modest_gtkhtml_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images);
74 static void     modest_gtkhtml_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images);
75 static gboolean modest_gtkhtml_mime_part_view_has_external_images (ModestMimePartView *self);
76 static gboolean modest_gtkhtml_mime_part_view_has_external_images_default (ModestMimePartView *self);
77 /* ModestZoomable implementation */
78 static gdouble modest_gtkhtml_mime_part_view_get_zoom (ModestZoomable *self);
79 static void modest_gtkhtml_mime_part_view_set_zoom (ModestZoomable *self, gdouble value);
80 static gboolean modest_gtkhtml_mime_part_view_zoom_minus (ModestZoomable *self);
81 static gboolean modest_gtkhtml_mime_part_view_zoom_plus (ModestZoomable *self);
82 static gdouble modest_gtkhtml_mime_part_view_get_zoom_default (ModestZoomable *self);
83 static void modest_gtkhtml_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value);
84 static gboolean modest_gtkhtml_mime_part_view_zoom_minus_default (ModestZoomable *self);
85 static gboolean modest_gtkhtml_mime_part_view_zoom_plus_default (ModestZoomable *self);
86 /* ModestISearchView implementation */
87 static gboolean modest_gtkhtml_mime_part_view_search                    (ModestISearchView *self, const gchar *string);
88 static gboolean modest_gtkhtml_mime_part_view_search_next               (ModestISearchView *self);
89 static gboolean modest_gtkhtml_mime_part_view_get_selection_area        (ModestISearchView *self, gint *x, gint *y, 
90                                                                          gint *width, gint *height);
91 static gboolean modest_gtkhtml_mime_part_view_search_default            (ModestISearchView *self, const gchar *string);
92 static gboolean modest_gtkhtml_mime_part_view_search_next_default       (ModestISearchView *self);
93 static gboolean modest_gtkhtml_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
94                                                                           gint *width, gint *height);
95
96
97 /* internal api */
98 static TnyMimePart  *get_part   (ModestGtkhtmlMimePartView *self);
99 static void          set_html_part   (ModestGtkhtmlMimePartView *self, TnyMimePart *part);
100 static void          set_text_part   (ModestGtkhtmlMimePartView *self, TnyMimePart *part);
101 static void          set_empty_part  (ModestGtkhtmlMimePartView *self);
102 static void          set_part   (ModestGtkhtmlMimePartView *self, TnyMimePart *part);
103 static gboolean      is_empty   (ModestGtkhtmlMimePartView *self);
104 static gboolean      get_view_images   (ModestGtkhtmlMimePartView *self);
105 static void          set_view_images   (ModestGtkhtmlMimePartView *self, gboolean view_images);
106 static gboolean      has_external_images   (ModestGtkhtmlMimePartView *self);
107 static void          set_zoom   (ModestGtkhtmlMimePartView *self, gdouble zoom);
108 static gdouble       get_zoom   (ModestGtkhtmlMimePartView *self);
109 static gboolean      has_contents_receiver (gpointer engine, const gchar *data,
110                                             size_t len, gboolean *has_contents);
111 static gboolean      search             (ModestGtkhtmlMimePartView *self, const gchar *string);
112 static gboolean      search_next        (ModestGtkhtmlMimePartView *self);
113 static gboolean      get_selection_area (ModestGtkhtmlMimePartView *self, gint *x, gint *y,
114                                          gint *width, gint *height);
115
116 typedef struct _ModestGtkhtmlMimePartViewPrivate ModestGtkhtmlMimePartViewPrivate;
117 struct _ModestGtkhtmlMimePartViewPrivate {
118         TnyMimePart *part;
119         gdouble current_zoom;
120         gboolean view_images;
121         gboolean has_external_images;
122 };
123
124 #define MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
125                                                                                        MODEST_TYPE_GTKHTML_MIME_PART_VIEW, \
126                                                                                        ModestGtkhtmlMimePartViewPrivate))
127
128 static GtkHTMLClass *parent_class = NULL;
129
130 GtkWidget *
131 modest_gtkhtml_mime_part_view_new ()
132 {
133         return g_object_new (MODEST_TYPE_GTKHTML_MIME_PART_VIEW, NULL);
134 }
135
136 /* GOBJECT IMPLEMENTATION */
137 GType
138 modest_gtkhtml_mime_part_view_get_type (void)
139 {
140         static GType my_type = 0;
141         if (!my_type) {
142                 static const GTypeInfo my_info = {
143                         sizeof(ModestGtkhtmlMimePartViewClass),
144                         NULL,           /* base init */
145                         NULL,           /* base finalize */
146                         (GClassInitFunc) modest_gtkhtml_mime_part_view_class_init,
147                         NULL,           /* class finalize */
148                         NULL,           /* class data */
149                         sizeof(ModestGtkhtmlMimePartView),
150                         1,              /* n_preallocs */
151                         (GInstanceInitFunc) modest_gtkhtml_mime_part_view_init,
152                         NULL
153                 };
154
155                 static const GInterfaceInfo tny_mime_part_view_info = 
156                 {
157                   (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */
158                   NULL,         /* interface_finalize */
159                   NULL          /* interface_data */
160                 };
161
162                 static const GInterfaceInfo modest_mime_part_view_info = 
163                 {
164                   (GInterfaceInitFunc) modest_mime_part_view_init, /* interface_init */
165                   NULL,         /* interface_finalize */
166                   NULL          /* interface_data */
167                 };
168
169                 static const GInterfaceInfo modest_zoomable_info = 
170                 {
171                   (GInterfaceInitFunc) modest_zoomable_init, /* interface_init */
172                   NULL,         /* interface_finalize */
173                   NULL          /* interface_data */
174                 };
175
176                 static const GInterfaceInfo modest_isearch_view_info = 
177                 {
178                   (GInterfaceInitFunc) modest_isearch_view_init, /* interface_init */
179                   NULL,         /* interface_finalize */
180                   NULL          /* interface_data */
181                 };
182
183                 my_type = g_type_register_static (GTK_TYPE_HTML,
184                                                   "ModestGtkhtmlMimePartView",
185                                                   &my_info, 0);
186
187                 g_type_add_interface_static (my_type, TNY_TYPE_MIME_PART_VIEW, 
188                         &tny_mime_part_view_info);
189
190                 g_type_add_interface_static (my_type, MODEST_TYPE_MIME_PART_VIEW, 
191                         &modest_mime_part_view_info);
192
193                 g_type_add_interface_static (my_type, MODEST_TYPE_ZOOMABLE, 
194                         &modest_zoomable_info);
195                 g_type_add_interface_static (my_type, MODEST_TYPE_ISEARCH_VIEW, 
196                         &modest_isearch_view_info);
197         }
198         return my_type;
199 }
200
201 static void
202 modest_gtkhtml_mime_part_view_class_init (ModestGtkhtmlMimePartViewClass *klass)
203 {
204         GObjectClass *gobject_class;
205         GtkBindingSet *binding_set;
206
207         gobject_class = (GObjectClass*) klass;
208
209         parent_class            = g_type_class_peek_parent (klass);
210         gobject_class->dispose = modest_gtkhtml_mime_part_view_dispose;
211         gobject_class->finalize = modest_gtkhtml_mime_part_view_finalize;
212
213         klass->get_part_func = modest_gtkhtml_mime_part_view_get_part_default;
214         klass->set_part_func = modest_gtkhtml_mime_part_view_set_part_default;
215         klass->clear_func = modest_gtkhtml_mime_part_view_clear_default;
216         klass->is_empty_func = modest_gtkhtml_mime_part_view_is_empty_default;
217         klass->get_view_images_func = modest_gtkhtml_mime_part_view_get_view_images_default;
218         klass->set_view_images_func = modest_gtkhtml_mime_part_view_set_view_images_default;
219         klass->has_external_images_func = modest_gtkhtml_mime_part_view_has_external_images_default;
220         klass->get_zoom_func = modest_gtkhtml_mime_part_view_get_zoom_default;
221         klass->set_zoom_func = modest_gtkhtml_mime_part_view_set_zoom_default;
222         klass->zoom_minus_func = modest_gtkhtml_mime_part_view_zoom_minus_default;
223         klass->zoom_plus_func = modest_gtkhtml_mime_part_view_zoom_plus_default;
224         klass->search_func = modest_gtkhtml_mime_part_view_search_default;
225         klass->search_next_func = modest_gtkhtml_mime_part_view_search_next_default;
226         klass->get_selection_area_func = modest_gtkhtml_mime_part_view_get_selection_area_default;
227
228         binding_set = gtk_binding_set_by_class (klass);
229         gtk_binding_entry_skip (binding_set, GDK_Down, 0);
230         gtk_binding_entry_skip (binding_set, GDK_Up, 0);
231         gtk_binding_entry_skip (binding_set, GDK_KP_Up, 0);
232         gtk_binding_entry_skip (binding_set, GDK_KP_Down, 0);
233         gtk_binding_entry_skip (binding_set, GDK_Page_Down, 0);
234         gtk_binding_entry_skip (binding_set, GDK_Page_Up, 0);
235         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Up, 0);
236         gtk_binding_entry_skip (binding_set, GDK_KP_Page_Down, 0);
237         gtk_binding_entry_skip (binding_set, GDK_Home, 0);
238         gtk_binding_entry_skip (binding_set, GDK_End, 0);
239         gtk_binding_entry_skip (binding_set, GDK_KP_Home, 0);
240         gtk_binding_entry_skip (binding_set, GDK_KP_End, 0);
241         
242         g_type_class_add_private (gobject_class, sizeof(ModestGtkhtmlMimePartViewPrivate));
243
244 }
245
246 static void    
247 modest_gtkhtml_mime_part_view_init (ModestGtkhtmlMimePartView *self)
248 {
249         ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
250
251         gtk_html_set_editable        (GTK_HTML(self), FALSE);
252         gtk_html_allow_selection     (GTK_HTML(self), TRUE);
253         gtk_html_set_caret_mode      (GTK_HTML(self), FALSE);
254         gtk_html_set_blocking        (GTK_HTML(self), TRUE);
255         gtk_html_set_images_blocking (GTK_HTML(self), TRUE);
256
257         g_signal_connect (G_OBJECT(self), "link_clicked",
258                           G_CALLBACK(on_link_clicked), self);
259         g_signal_connect (G_OBJECT(self), "url_requested",
260                           G_CALLBACK(on_url_requested), self);
261         g_signal_connect (G_OBJECT(self), "on_url",
262                           G_CALLBACK(on_url), self);
263
264         priv->part = NULL;
265         priv->current_zoom = 1.0;
266         priv->view_images = FALSE;
267         priv->has_external_images = FALSE;
268 }
269
270 static void
271 modest_gtkhtml_mime_part_view_finalize (GObject *obj)
272 {
273         G_OBJECT_CLASS (parent_class)->finalize (obj);
274 }
275
276 static void
277 modest_gtkhtml_mime_part_view_dispose (GObject *obj)
278 {
279         ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (obj);
280
281         if (priv->part) {
282                 g_object_unref (priv->part);
283                 priv->part = NULL;
284         }
285
286         G_OBJECT_CLASS (parent_class)->dispose (obj);
287 }
288
289 /* GTKHTML SIGNALS HANDLERS */
290
291 static gboolean
292 on_link_clicked (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self)
293 {
294         gboolean result;
295         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
296
297         g_signal_emit_by_name (G_OBJECT (self), "activate-link", uri, &result);
298         return result;
299 }
300
301 static gboolean
302 on_url (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self)
303 {
304         gboolean result;
305         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
306
307         g_signal_emit_by_name (G_OBJECT (self), "link-hover", uri, &result);
308         return result;
309 }
310
311 typedef struct {
312         gpointer buffer;
313         GtkHTML *html;
314         GtkHTMLStream *stream;
315 } ImageFetcherInfo;
316
317 static gboolean
318 on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream, 
319                   ModestGtkhtmlMimePartView *self)
320 {
321         gboolean result;
322         TnyStream *tny_stream;
323         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
324
325         if (g_str_has_prefix (uri, "http:")) {
326                 ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
327
328                 if (!priv->view_images)
329                         priv->has_external_images = TRUE;
330         }
331                         
332         tny_stream = TNY_STREAM (modest_tny_stream_gtkhtml_new (stream, GTK_HTML (widget)));
333         g_signal_emit_by_name (MODEST_MIME_PART_VIEW (self), "fetch-url", uri, tny_stream, &result);
334         g_object_unref (tny_stream);
335         return result;
336 }
337
338 /* INTERNAL API */
339
340 static void
341 set_html_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
342 {
343         GtkHTMLStream *gtkhtml_stream;
344         TnyStream *tny_stream;  
345         
346         g_return_if_fail (self);
347         g_return_if_fail (part);
348         
349         gtkhtml_stream = gtk_html_begin(GTK_HTML(self));
350
351         tny_stream     = TNY_STREAM(modest_tny_stream_gtkhtml_new (gtkhtml_stream, GTK_HTML (self)));
352         tny_stream_reset (tny_stream);
353
354         tny_mime_part_decode_to_stream ((TnyMimePart*)part, tny_stream, NULL);
355         tny_stream_close (tny_stream);
356         g_object_unref (G_OBJECT(tny_stream));
357 }
358
359 static void
360 set_text_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
361 {
362         TnyStream* text_to_html_stream, *tny_stream;
363         GtkHTMLStream *gtkhtml_stream;
364         
365         g_return_if_fail (self);
366         g_return_if_fail (part);
367
368         gtkhtml_stream = gtk_html_begin(GTK_HTML(self)); 
369         tny_stream =  TNY_STREAM(modest_tny_stream_gtkhtml_new (gtkhtml_stream, GTK_HTML (self)));
370         text_to_html_stream = TNY_STREAM (modest_stream_text_to_html_new (tny_stream));
371         modest_stream_text_to_html_set_linkify_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream), 64*1024);
372         modest_stream_text_to_html_set_full_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream), 640*1024);
373         
374         // FIXME: tinymail
375         tny_mime_part_decode_to_stream ((TnyMimePart*)part, text_to_html_stream, NULL);
376         tny_stream_write (text_to_html_stream, "\n", 1);
377         tny_stream_reset (text_to_html_stream);         
378         tny_stream_close (text_to_html_stream);
379         
380         g_object_unref (G_OBJECT(text_to_html_stream));
381         g_object_unref (G_OBJECT(tny_stream));
382         /* gtk_html_stream_destroy (gtkhtml_stream); */
383 }
384
385 static void
386 set_empty_part (ModestGtkhtmlMimePartView *self)
387 {
388         g_return_if_fail (self);
389
390         gtk_html_load_from_string (GTK_HTML(self),
391                                    "", 1);
392 }
393
394 static void
395 set_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
396 {
397         ModestGtkhtmlMimePartViewPrivate *priv;
398
399         g_return_if_fail (self);
400         
401         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self);
402         priv->has_external_images = FALSE;
403
404         if (part != priv->part) {
405                 if (priv->part)
406                         g_object_unref (G_OBJECT(priv->part));
407                 if (part)
408                         g_object_ref   (G_OBJECT(part));
409                 priv->part = part;
410         }
411         
412         if (!part) {
413                 set_empty_part (self);
414                 return;
415         }
416
417         if (tny_mime_part_content_type_is (part, "text/html"))
418                 set_html_part (self, part);
419         else
420                 set_text_part (self, part);
421
422 }
423
424 static TnyMimePart*
425 get_part (ModestGtkhtmlMimePartView *self)
426 {
427         TnyMimePart *part;
428
429         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), NULL);
430
431         part = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self)->part;
432
433         if (part)
434                 g_object_ref (part);
435         
436         return part;
437 }
438
439 static gboolean
440 has_contents_receiver (gpointer engine, const gchar *data,
441                        size_t len, gboolean *has_contents)
442 {
443         if (len > 1 || ((len == 1)&&(data[0]!='\n'))) {
444                 *has_contents = TRUE;
445                 return FALSE;
446         }
447         return TRUE;
448 }
449
450 static gboolean      
451 is_empty   (ModestGtkhtmlMimePartView *self)
452 {
453         /* TODO: Find some gtkhtml API to check whether there is any (visible, non markup)
454          * text in the message:
455          */
456         gboolean has_contents = FALSE;
457
458         gtk_html_export (GTK_HTML (self), "text/plain", 
459                          (GtkHTMLSaveReceiverFn) has_contents_receiver, &has_contents);
460         
461         return !has_contents;
462 }
463
464 static gboolean      
465 get_view_images   (ModestGtkhtmlMimePartView *self)
466 {
467         ModestGtkhtmlMimePartViewPrivate *priv;
468
469         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
470
471         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
472         return priv->view_images;
473 }
474
475 static void
476 set_view_images   (ModestGtkhtmlMimePartView *self, gboolean view_images)
477 {
478         ModestGtkhtmlMimePartViewPrivate *priv;
479
480         g_return_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self));
481
482         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
483         priv->view_images = view_images;
484 }
485
486 static gboolean      
487 has_external_images   (ModestGtkhtmlMimePartView *self)
488 {
489         ModestGtkhtmlMimePartViewPrivate *priv;
490
491         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
492
493         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
494         return priv->has_external_images;
495 }
496
497 static void
498 set_zoom (ModestGtkhtmlMimePartView *self, gdouble zoom)
499 {
500         ModestGtkhtmlMimePartViewPrivate *priv;
501
502         g_return_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self));
503
504         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
505         priv->current_zoom = zoom;
506         gtk_html_set_magnification (GTK_HTML(self), zoom);
507
508         gtk_widget_queue_resize (GTK_WIDGET (self));
509 }
510
511 static gdouble
512 get_zoom (ModestGtkhtmlMimePartView *self)
513 {
514         ModestGtkhtmlMimePartViewPrivate *priv;
515
516         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), 1.0);
517
518         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
519
520         return priv->current_zoom;
521 }
522
523 static gboolean
524 search (ModestGtkhtmlMimePartView *self, 
525         const gchar *string)
526 {
527         return gtk_html_engine_search (GTK_HTML (self),
528                                        string,
529                                        FALSE,   /* case sensitive */
530                                        TRUE,    /* forward */
531                                        FALSE);  /* regexp */
532 }
533
534 static gboolean
535 search_next (ModestGtkhtmlMimePartView *self)
536 {
537         return gtk_html_engine_search_next (GTK_HTML (self));
538 }
539
540 static gboolean
541 get_selection_area (ModestGtkhtmlMimePartView *self, 
542                     gint *x, gint *y,
543                     gint *width, gint *height)
544 {
545 #ifdef HAVE_GTK_HTML_GET_SELECTION_AREA
546         gtk_html_get_selection_area (GTK_HTML (self), x, y, width, height);
547         return TRUE;
548 #else
549         return FALSE;
550 #endif
551 }
552
553
554 /* TNY MIME PART IMPLEMENTATION */
555
556 static void
557 tny_mime_part_view_init (gpointer g, gpointer iface_data)
558 {
559         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
560
561         klass->get_part = modest_gtkhtml_mime_part_view_get_part;
562         klass->set_part = modest_gtkhtml_mime_part_view_set_part;
563         klass->clear = modest_gtkhtml_mime_part_view_clear;
564
565         return;
566 }
567
568 static TnyMimePart* 
569 modest_gtkhtml_mime_part_view_get_part (TnyMimePartView *self)
570 {
571         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
572 }
573
574
575 static TnyMimePart* 
576 modest_gtkhtml_mime_part_view_get_part_default (TnyMimePartView *self)
577 {
578         return TNY_MIME_PART (get_part (MODEST_GTKHTML_MIME_PART_VIEW (self)));
579 }
580
581 static void
582 modest_gtkhtml_mime_part_view_set_part (TnyMimePartView *self,
583                                         TnyMimePart *part)
584 {
585         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
586 }
587
588 static void
589 modest_gtkhtml_mime_part_view_set_part_default (TnyMimePartView *self,
590                                                 TnyMimePart *part)
591 {
592         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
593
594         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), part);
595 }
596
597 static void
598 modest_gtkhtml_mime_part_view_clear (TnyMimePartView *self)
599 {
600         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
601 }
602
603 static void
604 modest_gtkhtml_mime_part_view_clear_default (TnyMimePartView *self)
605 {
606         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), NULL);
607 }
608
609 /* MODEST MIME PART VIEW IMPLEMENTATION */
610
611 static void
612 modest_mime_part_view_init (gpointer g, gpointer iface_data)
613 {
614         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
615
616         klass->is_empty_func = modest_gtkhtml_mime_part_view_is_empty;
617         klass->get_view_images_func = modest_gtkhtml_mime_part_view_get_view_images;
618         klass->set_view_images_func = modest_gtkhtml_mime_part_view_set_view_images;
619         klass->has_external_images_func = modest_gtkhtml_mime_part_view_has_external_images;
620
621         return;
622 }
623
624 static gboolean
625 modest_gtkhtml_mime_part_view_is_empty (ModestMimePartView *self)
626 {
627         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
628 }
629
630 static gboolean
631 modest_gtkhtml_mime_part_view_get_view_images (ModestMimePartView *self)
632 {
633         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_view_images_func (self);
634 }
635
636 static void
637 modest_gtkhtml_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images)
638 {
639         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_view_images_func (self, view_images);
640 }
641
642 static gboolean
643 modest_gtkhtml_mime_part_view_has_external_images (ModestMimePartView *self)
644 {
645         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->has_external_images_func (self);
646 }
647
648 static gboolean
649 modest_gtkhtml_mime_part_view_is_empty_default (ModestMimePartView *self)
650 {
651         return is_empty (MODEST_GTKHTML_MIME_PART_VIEW (self));
652 }
653
654 static gboolean
655 modest_gtkhtml_mime_part_view_get_view_images_default (ModestMimePartView *self)
656 {
657         return get_view_images (MODEST_GTKHTML_MIME_PART_VIEW (self));
658 }
659
660 static void
661 modest_gtkhtml_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images)
662 {
663         set_view_images (MODEST_GTKHTML_MIME_PART_VIEW (self), view_images);
664 }
665
666 static gboolean
667 modest_gtkhtml_mime_part_view_has_external_images_default (ModestMimePartView *self)
668 {
669         return has_external_images (MODEST_GTKHTML_MIME_PART_VIEW (self));
670 }
671
672
673 /* MODEST ZOOMABLE IMPLEMENTATION */
674 static void
675 modest_zoomable_init (gpointer g, gpointer iface_data)
676 {
677         ModestZoomableIface *klass = (ModestZoomableIface *)g;
678         
679         klass->get_zoom_func = modest_gtkhtml_mime_part_view_get_zoom;
680         klass->set_zoom_func = modest_gtkhtml_mime_part_view_set_zoom;
681         klass->zoom_minus_func = modest_gtkhtml_mime_part_view_zoom_minus;
682         klass->zoom_plus_func = modest_gtkhtml_mime_part_view_zoom_plus;
683
684         return;
685 }
686
687 static gdouble
688 modest_gtkhtml_mime_part_view_get_zoom (ModestZoomable *self)
689 {
690         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
691 }
692
693 static gdouble
694 modest_gtkhtml_mime_part_view_get_zoom_default (ModestZoomable *self)
695 {
696         return get_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self));
697 }
698
699 static void
700 modest_gtkhtml_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
701 {
702         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
703 }
704
705 static void
706 modest_gtkhtml_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
707 {
708         set_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self), value);
709 }
710
711 static gboolean
712 modest_gtkhtml_mime_part_view_zoom_minus (ModestZoomable *self)
713 {
714         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
715 }
716
717 static gboolean
718 modest_gtkhtml_mime_part_view_zoom_minus_default (ModestZoomable *self)
719 {
720         /* operation not supported in ModestGtkhtmlMimePartView */
721         return FALSE;
722 }
723
724 static gboolean
725 modest_gtkhtml_mime_part_view_zoom_plus (ModestZoomable *self)
726 {
727         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
728 }
729
730 static gboolean
731 modest_gtkhtml_mime_part_view_zoom_plus_default (ModestZoomable *self)
732 {
733         /* operation not supported in ModestGtkhtmlMimePartView */
734         return FALSE;
735 }
736
737 /* ISEARCH VIEW IMPLEMENTATION */
738 static void
739 modest_isearch_view_init (gpointer g, gpointer iface_data)
740 {
741         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
742         
743         klass->search_func = modest_gtkhtml_mime_part_view_search;
744         klass->search_next_func = modest_gtkhtml_mime_part_view_search_next;
745         klass->get_selection_area_func = modest_gtkhtml_mime_part_view_get_selection_area;
746
747         return;
748 }
749
750 static gboolean 
751 modest_gtkhtml_mime_part_view_search (ModestISearchView *self, const gchar *string)
752 {
753         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
754 }
755
756 static gboolean 
757 modest_gtkhtml_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
758 {
759         return search (MODEST_GTKHTML_MIME_PART_VIEW (self), string);
760 }
761
762 static gboolean 
763 modest_gtkhtml_mime_part_view_search_next(ModestISearchView *self)
764 {
765         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
766 }
767
768 static gboolean 
769 modest_gtkhtml_mime_part_view_search_next_default (ModestISearchView *self)
770 {
771         return search_next (MODEST_GTKHTML_MIME_PART_VIEW (self));
772 }
773
774 static gboolean 
775 modest_gtkhtml_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
776                                                   gint *width, gint *height)
777 {
778         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
779 }
780
781 static gboolean 
782 modest_gtkhtml_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
783                                                           gint *width, gint *height)
784 {
785         return get_selection_area (MODEST_GTKHTML_MIME_PART_VIEW (self), x, y, width, height);
786 }