824021fe835f2ca2a5e642c786cb5b6f1400be1c
[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         gobject_class = (GObjectClass*) klass;
206
207         parent_class            = g_type_class_peek_parent (klass);
208         gobject_class->dispose = modest_gtkhtml_mime_part_view_dispose;
209         gobject_class->finalize = modest_gtkhtml_mime_part_view_finalize;
210
211         klass->get_part_func = modest_gtkhtml_mime_part_view_get_part_default;
212         klass->set_part_func = modest_gtkhtml_mime_part_view_set_part_default;
213         klass->clear_func = modest_gtkhtml_mime_part_view_clear_default;
214         klass->is_empty_func = modest_gtkhtml_mime_part_view_is_empty_default;
215         klass->get_view_images_func = modest_gtkhtml_mime_part_view_get_view_images_default;
216         klass->set_view_images_func = modest_gtkhtml_mime_part_view_set_view_images_default;
217         klass->has_external_images_func = modest_gtkhtml_mime_part_view_has_external_images_default;
218         klass->get_zoom_func = modest_gtkhtml_mime_part_view_get_zoom_default;
219         klass->set_zoom_func = modest_gtkhtml_mime_part_view_set_zoom_default;
220         klass->zoom_minus_func = modest_gtkhtml_mime_part_view_zoom_minus_default;
221         klass->zoom_plus_func = modest_gtkhtml_mime_part_view_zoom_plus_default;
222         klass->search_func = modest_gtkhtml_mime_part_view_search_default;
223         klass->search_next_func = modest_gtkhtml_mime_part_view_search_next_default;
224         klass->get_selection_area_func = modest_gtkhtml_mime_part_view_get_selection_area_default;
225         
226         g_type_class_add_private (gobject_class, sizeof(ModestGtkhtmlMimePartViewPrivate));
227
228 }
229
230 static void    
231 modest_gtkhtml_mime_part_view_init (ModestGtkhtmlMimePartView *self)
232 {
233         ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
234
235         gtk_html_set_editable        (GTK_HTML(self), FALSE);
236         gtk_html_allow_selection     (GTK_HTML(self), TRUE);
237         gtk_html_set_caret_mode      (GTK_HTML(self), FALSE);
238         gtk_html_set_blocking        (GTK_HTML(self), TRUE);
239         gtk_html_set_images_blocking (GTK_HTML(self), TRUE);
240
241         g_signal_connect (G_OBJECT(self), "link_clicked",
242                           G_CALLBACK(on_link_clicked), self);
243         g_signal_connect (G_OBJECT(self), "url_requested",
244                           G_CALLBACK(on_url_requested), self);
245         g_signal_connect (G_OBJECT(self), "on_url",
246                           G_CALLBACK(on_url), self);
247
248         priv->part = NULL;
249         priv->current_zoom = 1.0;
250         priv->view_images = FALSE;
251         priv->has_external_images = FALSE;
252 }
253
254 static void
255 modest_gtkhtml_mime_part_view_finalize (GObject *obj)
256 {
257         G_OBJECT_CLASS (parent_class)->finalize (obj);
258 }
259
260 static void
261 modest_gtkhtml_mime_part_view_dispose (GObject *obj)
262 {
263         ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (obj);
264
265         if (priv->part) {
266                 g_object_unref (priv->part);
267                 priv->part = NULL;
268         }
269
270         G_OBJECT_CLASS (parent_class)->dispose (obj);
271 }
272
273 /* GTKHTML SIGNALS HANDLERS */
274
275 static gboolean
276 on_link_clicked (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self)
277 {
278         gboolean result;
279         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
280
281         g_signal_emit_by_name (G_OBJECT (self), "activate-link", uri, &result);
282         return result;
283 }
284
285 static gboolean
286 on_url (GtkWidget *widget, const gchar *uri, ModestGtkhtmlMimePartView *self)
287 {
288         gboolean result;
289         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
290
291         g_signal_emit_by_name (G_OBJECT (self), "link-hover", uri, &result);
292         return result;
293 }
294
295 typedef struct {
296         gpointer buffer;
297         GtkHTML *html;
298         GtkHTMLStream *stream;
299 } ImageFetcherInfo;
300
301 static gboolean
302 on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream, 
303                   ModestGtkhtmlMimePartView *self)
304 {
305         gboolean result;
306         TnyStream *tny_stream;
307         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
308
309         if (g_str_has_prefix (uri, "http:")) {
310                 ModestGtkhtmlMimePartViewPrivate *priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
311
312                 if (!priv->view_images)
313                         priv->has_external_images = TRUE;
314         }
315                         
316         tny_stream = TNY_STREAM (modest_tny_stream_gtkhtml_new (stream, GTK_HTML (widget)));
317         g_signal_emit_by_name (MODEST_MIME_PART_VIEW (self), "fetch-url", uri, tny_stream, &result);
318         g_object_unref (tny_stream);
319         return result;
320 }
321
322 /* INTERNAL API */
323
324 static void
325 set_html_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
326 {
327         GtkHTMLStream *gtkhtml_stream;
328         TnyStream *tny_stream;  
329         
330         g_return_if_fail (self);
331         g_return_if_fail (part);
332         
333         gtkhtml_stream = gtk_html_begin(GTK_HTML(self));
334
335         tny_stream     = TNY_STREAM(modest_tny_stream_gtkhtml_new (gtkhtml_stream, GTK_HTML (self)));
336         tny_stream_reset (tny_stream);
337
338         tny_mime_part_decode_to_stream ((TnyMimePart*)part, tny_stream, NULL);
339         tny_stream_close (tny_stream);
340         g_object_unref (G_OBJECT(tny_stream));
341 }
342
343 static void
344 set_text_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
345 {
346         TnyStream* text_to_html_stream, *tny_stream;
347         GtkHTMLStream *gtkhtml_stream;
348         
349         g_return_if_fail (self);
350         g_return_if_fail (part);
351
352         gtkhtml_stream = gtk_html_begin(GTK_HTML(self)); 
353         tny_stream =  TNY_STREAM(modest_tny_stream_gtkhtml_new (gtkhtml_stream, GTK_HTML (self)));
354         text_to_html_stream = TNY_STREAM (modest_stream_text_to_html_new (tny_stream));
355         modest_stream_text_to_html_set_linkify_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream), 64*1024);
356         modest_stream_text_to_html_set_full_limit (MODEST_STREAM_TEXT_TO_HTML (text_to_html_stream), 640*1024);
357         
358         // FIXME: tinymail
359         tny_mime_part_decode_to_stream ((TnyMimePart*)part, text_to_html_stream, NULL);
360         tny_stream_write (text_to_html_stream, "\n", 1);
361         tny_stream_reset (text_to_html_stream);         
362         tny_stream_close (text_to_html_stream);
363         
364         g_object_unref (G_OBJECT(text_to_html_stream));
365         g_object_unref (G_OBJECT(tny_stream));
366         /* gtk_html_stream_destroy (gtkhtml_stream); */
367 }
368
369 static void
370 set_empty_part (ModestGtkhtmlMimePartView *self)
371 {
372         g_return_if_fail (self);
373
374         gtk_html_load_from_string (GTK_HTML(self),
375                                    "", 1);
376 }
377
378 static void
379 set_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
380 {
381         ModestGtkhtmlMimePartViewPrivate *priv;
382
383         g_return_if_fail (self);
384         
385         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self);
386         priv->has_external_images = FALSE;
387
388         if (part != priv->part) {
389                 if (priv->part)
390                         g_object_unref (G_OBJECT(priv->part));
391                 if (part)
392                         g_object_ref   (G_OBJECT(part));
393                 priv->part = part;
394         }
395         
396         if (!part) {
397                 set_empty_part (self);
398                 return;
399         }
400
401         if (tny_mime_part_content_type_is (part, "text/html"))
402                 set_html_part (self, part);
403         else
404                 set_text_part (self, part);
405
406 }
407
408 static TnyMimePart*
409 get_part (ModestGtkhtmlMimePartView *self)
410 {
411         TnyMimePart *part;
412
413         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), NULL);
414
415         part = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self)->part;
416
417         if (part)
418                 g_object_ref (part);
419         
420         return part;
421 }
422
423 static gboolean
424 has_contents_receiver (gpointer engine, const gchar *data,
425                        size_t len, gboolean *has_contents)
426 {
427         if (len > 1 || ((len == 1)&&(data[0]!='\n'))) {
428                 *has_contents = TRUE;
429                 return FALSE;
430         }
431         return TRUE;
432 }
433
434 static gboolean      
435 is_empty   (ModestGtkhtmlMimePartView *self)
436 {
437         /* TODO: Find some gtkhtml API to check whether there is any (visible, non markup)
438          * text in the message:
439          */
440         gboolean has_contents = FALSE;
441
442         gtk_html_export (GTK_HTML (self), "text/plain", 
443                          (GtkHTMLSaveReceiverFn) has_contents_receiver, &has_contents);
444         
445         return !has_contents;
446 }
447
448 static gboolean      
449 get_view_images   (ModestGtkhtmlMimePartView *self)
450 {
451         ModestGtkhtmlMimePartViewPrivate *priv;
452
453         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
454
455         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
456         return priv->view_images;
457 }
458
459 static void
460 set_view_images   (ModestGtkhtmlMimePartView *self, gboolean view_images)
461 {
462         ModestGtkhtmlMimePartViewPrivate *priv;
463
464         g_return_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self));
465
466         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
467         priv->view_images = view_images;
468 }
469
470 static gboolean      
471 has_external_images   (ModestGtkhtmlMimePartView *self)
472 {
473         ModestGtkhtmlMimePartViewPrivate *priv;
474
475         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), FALSE);
476
477         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
478         return priv->has_external_images;
479 }
480
481 static void
482 set_zoom (ModestGtkhtmlMimePartView *self, gdouble zoom)
483 {
484         ModestGtkhtmlMimePartViewPrivate *priv;
485
486         g_return_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self));
487
488         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
489         priv->current_zoom = zoom;
490         gtk_html_set_magnification (GTK_HTML(self), zoom);
491
492         gtk_widget_queue_resize (GTK_WIDGET (self));
493 }
494
495 static gdouble
496 get_zoom (ModestGtkhtmlMimePartView *self)
497 {
498         ModestGtkhtmlMimePartViewPrivate *priv;
499
500         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), 1.0);
501
502         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
503
504         return priv->current_zoom;
505 }
506
507 static gboolean
508 search (ModestGtkhtmlMimePartView *self, 
509         const gchar *string)
510 {
511         return gtk_html_engine_search (GTK_HTML (self),
512                                        string,
513                                        FALSE,   /* case sensitive */
514                                        TRUE,    /* forward */
515                                        FALSE);  /* regexp */
516 }
517
518 static gboolean
519 search_next (ModestGtkhtmlMimePartView *self)
520 {
521         return gtk_html_engine_search_next (GTK_HTML (self));
522 }
523
524 static gboolean
525 get_selection_area (ModestGtkhtmlMimePartView *self, 
526                     gint *x, gint *y,
527                     gint *width, gint *height)
528 {
529 #ifdef HAVE_GTK_HTML_GET_SELECTION_AREA
530         gtk_html_get_selection_area (GTK_HTML (self), x, y, width, height);
531         return TRUE;
532 #else
533         return FALSE;
534 #endif
535 }
536
537
538 /* TNY MIME PART IMPLEMENTATION */
539
540 static void
541 tny_mime_part_view_init (gpointer g, gpointer iface_data)
542 {
543         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
544
545         klass->get_part = modest_gtkhtml_mime_part_view_get_part;
546         klass->set_part = modest_gtkhtml_mime_part_view_set_part;
547         klass->clear = modest_gtkhtml_mime_part_view_clear;
548
549         return;
550 }
551
552 static TnyMimePart* 
553 modest_gtkhtml_mime_part_view_get_part (TnyMimePartView *self)
554 {
555         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
556 }
557
558
559 static TnyMimePart* 
560 modest_gtkhtml_mime_part_view_get_part_default (TnyMimePartView *self)
561 {
562         return TNY_MIME_PART (get_part (MODEST_GTKHTML_MIME_PART_VIEW (self)));
563 }
564
565 static void
566 modest_gtkhtml_mime_part_view_set_part (TnyMimePartView *self,
567                                         TnyMimePart *part)
568 {
569         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
570 }
571
572 static void
573 modest_gtkhtml_mime_part_view_set_part_default (TnyMimePartView *self,
574                                                 TnyMimePart *part)
575 {
576         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
577
578         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), part);
579 }
580
581 static void
582 modest_gtkhtml_mime_part_view_clear (TnyMimePartView *self)
583 {
584         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
585 }
586
587 static void
588 modest_gtkhtml_mime_part_view_clear_default (TnyMimePartView *self)
589 {
590         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), NULL);
591 }
592
593 /* MODEST MIME PART VIEW IMPLEMENTATION */
594
595 static void
596 modest_mime_part_view_init (gpointer g, gpointer iface_data)
597 {
598         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
599
600         klass->is_empty_func = modest_gtkhtml_mime_part_view_is_empty;
601         klass->get_view_images_func = modest_gtkhtml_mime_part_view_get_view_images;
602         klass->set_view_images_func = modest_gtkhtml_mime_part_view_set_view_images;
603         klass->has_external_images_func = modest_gtkhtml_mime_part_view_has_external_images;
604
605         return;
606 }
607
608 static gboolean
609 modest_gtkhtml_mime_part_view_is_empty (ModestMimePartView *self)
610 {
611         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
612 }
613
614 static gboolean
615 modest_gtkhtml_mime_part_view_get_view_images (ModestMimePartView *self)
616 {
617         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_view_images_func (self);
618 }
619
620 static void
621 modest_gtkhtml_mime_part_view_set_view_images (ModestMimePartView *self, gboolean view_images)
622 {
623         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_view_images_func (self, view_images);
624 }
625
626 static gboolean
627 modest_gtkhtml_mime_part_view_has_external_images (ModestMimePartView *self)
628 {
629         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->has_external_images_func (self);
630 }
631
632 static gboolean
633 modest_gtkhtml_mime_part_view_is_empty_default (ModestMimePartView *self)
634 {
635         return is_empty (MODEST_GTKHTML_MIME_PART_VIEW (self));
636 }
637
638 static gboolean
639 modest_gtkhtml_mime_part_view_get_view_images_default (ModestMimePartView *self)
640 {
641         return get_view_images (MODEST_GTKHTML_MIME_PART_VIEW (self));
642 }
643
644 static void
645 modest_gtkhtml_mime_part_view_set_view_images_default (ModestMimePartView *self, gboolean view_images)
646 {
647         set_view_images (MODEST_GTKHTML_MIME_PART_VIEW (self), view_images);
648 }
649
650 static gboolean
651 modest_gtkhtml_mime_part_view_has_external_images_default (ModestMimePartView *self)
652 {
653         return has_external_images (MODEST_GTKHTML_MIME_PART_VIEW (self));
654 }
655
656
657 /* MODEST ZOOMABLE IMPLEMENTATION */
658 static void
659 modest_zoomable_init (gpointer g, gpointer iface_data)
660 {
661         ModestZoomableIface *klass = (ModestZoomableIface *)g;
662         
663         klass->get_zoom_func = modest_gtkhtml_mime_part_view_get_zoom;
664         klass->set_zoom_func = modest_gtkhtml_mime_part_view_set_zoom;
665         klass->zoom_minus_func = modest_gtkhtml_mime_part_view_zoom_minus;
666         klass->zoom_plus_func = modest_gtkhtml_mime_part_view_zoom_plus;
667
668         return;
669 }
670
671 static gdouble
672 modest_gtkhtml_mime_part_view_get_zoom (ModestZoomable *self)
673 {
674         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
675 }
676
677 static gdouble
678 modest_gtkhtml_mime_part_view_get_zoom_default (ModestZoomable *self)
679 {
680         return get_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self));
681 }
682
683 static void
684 modest_gtkhtml_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
685 {
686         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
687 }
688
689 static void
690 modest_gtkhtml_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
691 {
692         set_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self), value);
693 }
694
695 static gboolean
696 modest_gtkhtml_mime_part_view_zoom_minus (ModestZoomable *self)
697 {
698         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
699 }
700
701 static gboolean
702 modest_gtkhtml_mime_part_view_zoom_minus_default (ModestZoomable *self)
703 {
704         /* operation not supported in ModestGtkhtmlMimePartView */
705         return FALSE;
706 }
707
708 static gboolean
709 modest_gtkhtml_mime_part_view_zoom_plus (ModestZoomable *self)
710 {
711         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
712 }
713
714 static gboolean
715 modest_gtkhtml_mime_part_view_zoom_plus_default (ModestZoomable *self)
716 {
717         /* operation not supported in ModestGtkhtmlMimePartView */
718         return FALSE;
719 }
720
721 /* ISEARCH VIEW IMPLEMENTATION */
722 static void
723 modest_isearch_view_init (gpointer g, gpointer iface_data)
724 {
725         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
726         
727         klass->search_func = modest_gtkhtml_mime_part_view_search;
728         klass->search_next_func = modest_gtkhtml_mime_part_view_search_next;
729         klass->get_selection_area_func = modest_gtkhtml_mime_part_view_get_selection_area;
730
731         return;
732 }
733
734 static gboolean 
735 modest_gtkhtml_mime_part_view_search (ModestISearchView *self, const gchar *string)
736 {
737         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
738 }
739
740 static gboolean 
741 modest_gtkhtml_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
742 {
743         return search (MODEST_GTKHTML_MIME_PART_VIEW (self), string);
744 }
745
746 static gboolean 
747 modest_gtkhtml_mime_part_view_search_next(ModestISearchView *self)
748 {
749         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
750 }
751
752 static gboolean 
753 modest_gtkhtml_mime_part_view_search_next_default (ModestISearchView *self)
754 {
755         return search_next (MODEST_GTKHTML_MIME_PART_VIEW (self));
756 }
757
758 static gboolean 
759 modest_gtkhtml_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
760                                                   gint *width, gint *height)
761 {
762         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
763 }
764
765 static gboolean 
766 modest_gtkhtml_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
767                                                           gint *width, gint *height)
768 {
769         return get_selection_area (MODEST_GTKHTML_MIME_PART_VIEW (self), x, y, width, height);
770 }