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