This commit includes a complete refactor of ModestMsgView. Now
[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 <tny-gtk-text-buffer-stream.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         GtkTextBuffer *buf;
302         GtkTextIter begin, end;
303         TnyStream* txt_stream, *tny_stream;
304         GtkHTMLStream *gtkhtml_stream;
305         gchar *txt;
306                 
307         g_return_if_fail (self);
308         g_return_if_fail (part);
309
310         buf            = gtk_text_buffer_new (NULL);
311         txt_stream     = TNY_STREAM(tny_gtk_text_buffer_stream_new (buf));
312                 
313         tny_stream_reset (txt_stream);
314
315         gtkhtml_stream = gtk_html_begin(GTK_HTML(self)); 
316         tny_stream =  TNY_STREAM(modest_tny_stream_gtkhtml_new (gtkhtml_stream));
317         
318         // FIXME: tinymail
319         tny_mime_part_decode_to_stream ((TnyMimePart*)part, txt_stream);
320         tny_stream_reset (txt_stream);          
321         
322         gtk_text_buffer_get_bounds (buf, &begin, &end);
323         txt = gtk_text_buffer_get_text (buf, &begin, &end, FALSE);
324         if (txt) {
325                 gchar *html = modest_text_utils_convert_to_html (txt);
326                 tny_stream_write (tny_stream, html, strlen(html));
327                 tny_stream_reset (tny_stream);
328                 g_free (txt);
329                 g_free (html);
330         }
331         
332         g_object_unref (G_OBJECT(tny_stream));
333         g_object_unref (G_OBJECT(txt_stream));
334         g_object_unref (G_OBJECT(buf));
335         
336         gtk_html_stream_destroy (gtkhtml_stream);
337 }
338
339 static void
340 set_empty_part (ModestGtkhtmlMimePartView *self)
341 {
342         g_return_if_fail (self);
343
344         gtk_html_load_from_string (GTK_HTML(self),
345                                    "", 1);
346 }
347
348 static void
349 set_part (ModestGtkhtmlMimePartView *self, TnyMimePart *part)
350 {
351         ModestGtkhtmlMimePartViewPrivate *priv;
352
353         g_return_if_fail (self);
354         
355         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self);
356
357         if (part != priv->part) {
358                 if (priv->part)
359                         g_object_unref (G_OBJECT(priv->part));
360                 if (part)
361                         g_object_ref   (G_OBJECT(part));
362                 priv->part = part;
363         }
364         
365         if (!part) {
366                 set_empty_part (self);
367                 return;
368         }
369
370         if (tny_mime_part_content_type_is (part, "text/html"))
371                 set_html_part (self, part);
372         else
373                 set_text_part (self, part);
374
375 }
376
377 static TnyMimePart*
378 get_part (ModestGtkhtmlMimePartView *self)
379 {
380         TnyMimePart *part;
381
382         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), NULL);
383
384         part = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE(self)->part;
385
386         if (part)
387                 g_object_ref (part);
388         
389         return part;
390 }
391
392 static gboolean
393 has_contents_receiver (gpointer engine, const gchar *data,
394                        size_t len, gboolean *has_contents)
395 {
396         if (len > 1 || ((len == 1)&&(data[0]!='\n'))) {
397                 *has_contents = TRUE;
398                 return FALSE;
399         }
400         return TRUE;
401 }
402
403 static gboolean      
404 is_empty   (ModestGtkhtmlMimePartView *self)
405 {
406         /* TODO: Find some gtkhtml API to check whether there is any (visible, non markup)
407          * text in the message:
408          */
409         gboolean has_contents = FALSE;
410
411         gtk_html_export (GTK_HTML (self), "text/plain", 
412                          (GtkHTMLSaveReceiverFn) has_contents_receiver, &has_contents);
413         
414         return !has_contents;
415 }
416
417 static void
418 set_zoom (ModestGtkhtmlMimePartView *self, gdouble zoom)
419 {
420         ModestGtkhtmlMimePartViewPrivate *priv;
421
422         g_return_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self));
423
424         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
425         priv->current_zoom = zoom;
426         gtk_html_set_magnification (GTK_HTML(self), zoom);
427
428         gtk_widget_queue_resize (GTK_WIDGET (self));
429 }
430
431 static gdouble
432 get_zoom (ModestGtkhtmlMimePartView *self)
433 {
434         ModestGtkhtmlMimePartViewPrivate *priv;
435
436         g_return_val_if_fail (MODEST_IS_GTKHTML_MIME_PART_VIEW (self), 1.0);
437
438         priv = MODEST_GTKHTML_MIME_PART_VIEW_GET_PRIVATE (self);
439
440         return priv->current_zoom;
441 }
442
443 static gboolean
444 search (ModestGtkhtmlMimePartView *self, 
445         const gchar *string)
446 {
447         return gtk_html_engine_search (GTK_HTML (self),
448                                        string,
449                                        FALSE,   /* case sensitive */
450                                        TRUE,    /* forward */
451                                        FALSE);  /* regexp */
452 }
453
454 static gboolean
455 search_next (ModestGtkhtmlMimePartView *self)
456 {
457         return gtk_html_engine_search_next (GTK_HTML (self));
458 }
459
460 static gboolean
461 get_selection_area (ModestGtkhtmlMimePartView *self, 
462                     gint *x, gint *y,
463                     gint *width, gint *height)
464 {
465 #ifdef HAVE_GTK_HTML_GET_SELECTION_AREA
466         gtk_html_get_selection_area (GTK_HTML (self), x, y, width, height);
467         return TRUE;
468 #else
469         return FALSE;
470 #endif
471 }
472
473
474 /* TNY MIME PART IMPLEMENTATION */
475
476 static void
477 tny_mime_part_view_init (gpointer g, gpointer iface_data)
478 {
479         TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g;
480
481         klass->get_part_func = modest_gtkhtml_mime_part_view_get_part;
482         klass->set_part_func = modest_gtkhtml_mime_part_view_set_part;
483         klass->clear_func = modest_gtkhtml_mime_part_view_clear;
484
485         return;
486 }
487
488 static TnyMimePart* 
489 modest_gtkhtml_mime_part_view_get_part (TnyMimePartView *self)
490 {
491         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_part_func (self);
492 }
493
494
495 static TnyMimePart* 
496 modest_gtkhtml_mime_part_view_get_part_default (TnyMimePartView *self)
497 {
498         return TNY_MIME_PART (get_part (MODEST_GTKHTML_MIME_PART_VIEW (self)));
499 }
500
501 static void
502 modest_gtkhtml_mime_part_view_set_part (TnyMimePartView *self,
503                                         TnyMimePart *part)
504 {
505         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_part_func (self, part);
506 }
507
508 static void
509 modest_gtkhtml_mime_part_view_set_part_default (TnyMimePartView *self,
510                                                 TnyMimePart *part)
511 {
512         g_return_if_fail ((part == NULL) || TNY_IS_MIME_PART (part));
513
514         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), part);
515 }
516
517 static void
518 modest_gtkhtml_mime_part_view_clear (TnyMimePartView *self)
519 {
520         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->clear_func (self);
521 }
522
523 static void
524 modest_gtkhtml_mime_part_view_clear_default (TnyMimePartView *self)
525 {
526         set_part (MODEST_GTKHTML_MIME_PART_VIEW (self), NULL);
527 }
528
529 /* MODEST MIME PART VIEW IMPLEMENTATION */
530
531 static void
532 modest_mime_part_view_init (gpointer g, gpointer iface_data)
533 {
534         ModestMimePartViewIface *klass = (ModestMimePartViewIface *)g;
535
536         klass->is_empty_func = modest_gtkhtml_mime_part_view_is_empty;
537
538         return;
539 }
540
541 static gboolean
542 modest_gtkhtml_mime_part_view_is_empty (ModestMimePartView *self)
543 {
544         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->is_empty_func (self);
545 }
546
547 static gboolean
548 modest_gtkhtml_mime_part_view_is_empty_default (ModestMimePartView *self)
549 {
550         return is_empty (MODEST_GTKHTML_MIME_PART_VIEW (self));
551 }
552
553
554 /* MODEST ZOOMABLE IMPLEMENTATION */
555 static void
556 modest_zoomable_init (gpointer g, gpointer iface_data)
557 {
558         ModestZoomableIface *klass = (ModestZoomableIface *)g;
559         
560         klass->get_zoom_func = modest_gtkhtml_mime_part_view_get_zoom;
561         klass->set_zoom_func = modest_gtkhtml_mime_part_view_set_zoom;
562         klass->zoom_minus_func = modest_gtkhtml_mime_part_view_zoom_minus;
563         klass->zoom_plus_func = modest_gtkhtml_mime_part_view_zoom_plus;
564
565         return;
566 }
567
568 static gdouble
569 modest_gtkhtml_mime_part_view_get_zoom (ModestZoomable *self)
570 {
571         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_zoom_func (self);
572 }
573
574 static gdouble
575 modest_gtkhtml_mime_part_view_get_zoom_default (ModestZoomable *self)
576 {
577         return get_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self));
578 }
579
580 static void
581 modest_gtkhtml_mime_part_view_set_zoom (ModestZoomable *self, gdouble value)
582 {
583         MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->set_zoom_func (self, value);
584 }
585
586 static void
587 modest_gtkhtml_mime_part_view_set_zoom_default (ModestZoomable *self, gdouble value)
588 {
589         set_zoom (MODEST_GTKHTML_MIME_PART_VIEW (self), value);
590 }
591
592 static gboolean
593 modest_gtkhtml_mime_part_view_zoom_minus (ModestZoomable *self)
594 {
595         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_minus_func (self);
596 }
597
598 static gboolean
599 modest_gtkhtml_mime_part_view_zoom_minus_default (ModestZoomable *self)
600 {
601         /* operation not supported in ModestGtkhtmlMimePartView */
602         return FALSE;
603 }
604
605 static gboolean
606 modest_gtkhtml_mime_part_view_zoom_plus (ModestZoomable *self)
607 {
608         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->zoom_plus_func (self);
609 }
610
611 static gboolean
612 modest_gtkhtml_mime_part_view_zoom_plus_default (ModestZoomable *self)
613 {
614         /* operation not supported in ModestGtkhtmlMimePartView */
615         return FALSE;
616 }
617
618 /* ISEARCH VIEW IMPLEMENTATION */
619 static void
620 modest_isearch_view_init (gpointer g, gpointer iface_data)
621 {
622         ModestISearchViewIface *klass = (ModestISearchViewIface *)g;
623         
624         klass->search_func = modest_gtkhtml_mime_part_view_search;
625         klass->search_next_func = modest_gtkhtml_mime_part_view_search_next;
626         klass->get_selection_area_func = modest_gtkhtml_mime_part_view_get_selection_area;
627
628         return;
629 }
630
631 static gboolean 
632 modest_gtkhtml_mime_part_view_search (ModestISearchView *self, const gchar *string)
633 {
634         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_func (self, string);
635 }
636
637 static gboolean 
638 modest_gtkhtml_mime_part_view_search_default (ModestISearchView *self, const gchar *string)
639 {
640         return search (MODEST_GTKHTML_MIME_PART_VIEW (self), string);
641 }
642
643 static gboolean 
644 modest_gtkhtml_mime_part_view_search_next(ModestISearchView *self)
645 {
646         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->search_next_func (self);
647 }
648
649 static gboolean 
650 modest_gtkhtml_mime_part_view_search_next_default (ModestISearchView *self)
651 {
652         return search_next (MODEST_GTKHTML_MIME_PART_VIEW (self));
653 }
654
655 static gboolean 
656 modest_gtkhtml_mime_part_view_get_selection_area (ModestISearchView *self, gint *x, gint *y, 
657                                                   gint *width, gint *height)
658 {
659         return MODEST_GTKHTML_MIME_PART_VIEW_GET_CLASS (self)->get_selection_area_func (self, x, y, width, height);
660 }
661
662 static gboolean 
663 modest_gtkhtml_mime_part_view_get_selection_area_default (ModestISearchView *self, gint *x, gint *y, 
664                                                           gint *width, gint *height)
665 {
666         return get_selection_area (MODEST_GTKHTML_MIME_PART_VIEW (self), x, y, width, height);
667 }