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