* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-msg-edit-window.c
1 /* Copyright (c) 2006, 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 <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37
38 #include <config.h>
39
40 #include <modest-account-mgr.h>
41 #include <modest-account-mgr-helpers.h>
42
43 #include <widgets/modest-msg-edit-window.h>
44 #include <widgets/modest-combo-box.h>
45
46 #include <modest-runtime.h>
47
48 #include "modest-icon-names.h"
49 #include "modest-widget-memory.h"
50 #include "modest-window-priv.h"
51 #include "modest-mail-operation.h"
52 #include "modest-tny-platform-factory.h"
53 #include "modest-tny-msg.h"
54 #include <tny-simple-list.h>
55 #include <wptextview.h>
56 #include <wptextbuffer.h>
57 #include <hildon-widgets/hildon-color-selector.h>
58 #include <hildon-widgets/hildon-color-button.h>
59 #include <hildon-widgets/hildon-banner.h>
60 #include <hildon-widgets/hildon-caption.h>
61
62 #ifdef MODEST_HILDON_VERSION_0
63 #include <hildon-widgets/hildon-file-chooser-dialog.h>
64 #else
65 #include <hildon/hildon-file-chooser-dialog.h>
66 #include <widgets/modest-msg-edit-window-ui.h>
67
68 #endif /*MODEST_HILDON_VERSION_0 */
69
70
71
72 #define DEFAULT_FONT_SIZE 3
73 #define DEFAULT_FONT 2
74 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
75 #define DEFAULT_MAIN_VBOX_SPACING 6
76 #define SUBJECT_MAX_LENGTH 1000
77
78 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
79 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
80 static void  modest_msg_edit_window_finalize     (GObject *obj);
81
82 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
83 static void  text_buffer_mark_set (GtkTextBuffer *buffer, GtkTextIter *location, GtkTextMark *mark, gpointer userdata);
84 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
85                                                          gpointer userdata);
86 static void  modest_msg_edit_window_size_combobox_change (ModestMsgEditWindow *window,
87                                                           gpointer userdata);
88 static void  modest_msg_edit_window_font_combobox_change (ModestMsgEditWindow *window,
89                                                           gpointer userdata);
90 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
91 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
92                                                            GdkEventWindowState *event, 
93                                                            gpointer userdata);
94
95 /* ModestWindow methods implementation */
96 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
97 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
98 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
99 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
100
101
102
103 /* list my signals */
104 enum {
105         /* MY_SIGNAL_1, */
106         /* MY_SIGNAL_2, */
107         LAST_SIGNAL
108 };
109
110 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
111 struct _ModestMsgEditWindowPrivate {
112         GtkWidget   *msg_body;
113         GtkWidget   *header_box;
114         GtkWidget   *from_field;
115         GtkWidget   *to_field;
116         GtkWidget   *cc_field;
117         GtkWidget   *bcc_field;
118         GtkWidget   *subject_field;
119
120         GtkWidget   *cc_caption;
121         GtkWidget   *bcc_caption;
122
123         GtkTextBuffer *text_buffer;
124
125         GtkWidget   *font_color_button;
126         GtkWidget   *size_combobox;
127         GtkWidget   *font_combobox;
128
129         GtkWidget   *scroll;
130
131         gint last_cid;
132         GList *attachments;
133
134         gdouble zoom_level;
135 };
136
137 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
138                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
139                                                     ModestMsgEditWindowPrivate))
140 /* globals */
141 static GtkWindowClass *parent_class = NULL;
142
143 /* uncomment the following if you have defined any signals */
144 /* static guint signals[LAST_SIGNAL] = {0}; */
145
146 GType
147 modest_msg_edit_window_get_type (void)
148 {
149         static GType my_type = 0;
150         if (!my_type) {
151                 static const GTypeInfo my_info = {
152                         sizeof(ModestMsgEditWindowClass),
153                         NULL,           /* base init */
154                         NULL,           /* base finalize */
155                         (GClassInitFunc) modest_msg_edit_window_class_init,
156                         NULL,           /* class finalize */
157                         NULL,           /* class data */
158                         sizeof(ModestMsgEditWindow),
159                         1,              /* n_preallocs */
160                         (GInstanceInitFunc) modest_msg_edit_window_init,
161                         NULL
162                 };
163                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
164                                                   "ModestMsgEditWindow",
165                                                   &my_info, 0);
166
167                 wp_text_buffer_library_init ();
168         }
169         return my_type;
170 }
171
172 static void
173 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
174 {
175         GObjectClass *gobject_class;
176         ModestWindowClass *modest_window_class;
177         gobject_class = (GObjectClass*) klass;
178         modest_window_class = (ModestWindowClass*) klass;
179
180         parent_class            = g_type_class_peek_parent (klass);
181         gobject_class->finalize = modest_msg_edit_window_finalize;
182
183         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
184         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
185         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
186         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
187
188         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
189 }
190
191 static void
192 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
193 {
194         ModestMsgEditWindowPrivate *priv;
195         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
196
197         priv->msg_body      = NULL;
198         priv->from_field    = NULL;
199         priv->to_field      = NULL;
200         priv->cc_field      = NULL;
201         priv->bcc_field     = NULL;
202         priv->subject_field = NULL;
203         priv->attachments   = NULL;
204         priv->last_cid      = 0;
205         priv->zoom_level    = 1.0;
206
207         priv->cc_caption    = NULL;
208         priv->bcc_caption    = NULL;
209 }
210
211
212
213 static void
214 save_settings (ModestMsgEditWindow *self)
215 {
216         modest_widget_memory_save (modest_runtime_get_conf(),
217                                    G_OBJECT(self), "modest-edit-msg-window");
218 }
219
220
221 static void
222 restore_settings (ModestMsgEditWindow *self)
223 {
224         modest_widget_memory_restore (modest_runtime_get_conf(),
225                                       G_OBJECT(self), "modest-edit-msg-window");
226 }
227
228
229 /* FIXME: this is a dup from the one in gtk/ */
230 static ModestPairList*
231 get_transports (void)
232 {
233         ModestAccountMgr *account_mgr;
234         GSList *transports = NULL;
235         GSList *cursor, *accounts;
236         
237         account_mgr = modest_runtime_get_account_mgr();
238         cursor = accounts = modest_account_mgr_account_names (account_mgr); 
239         while (cursor) {
240                 gchar *account_name = (gchar*)cursor->data;
241                 gchar *from_string  = modest_account_mgr_get_from_string (account_mgr,
242                                                                           account_name);
243                 if (!from_string)  {
244                         /* something went wrong: ignore this one */
245                         g_free (account_name);
246                         cursor->data = NULL;
247                 } else {
248                         ModestPair *pair;
249                         pair = modest_pair_new ((gpointer) account_name,
250                                                 (gpointer) from_string , TRUE);
251                         transports = g_slist_prepend (transports, pair);
252                 } /* don't free account name; it's freed when the transports list is freed */
253                 cursor = cursor->next;
254         }
255         g_slist_free (accounts);
256         return transports;
257 }
258
259
260 static void
261 text_buffer_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark, gpointer userdata)
262 {
263         ModestMsgEditWindow *window;
264         ModestMsgEditWindowPrivate *priv;
265         GdkRectangle location;
266         gint v_scroll_min_value = 0;
267         gint v_scroll_max_value = 0;
268         gint v_scroll_visible;
269         GtkAdjustment *vadj;
270         GtkTextMark *insert_mark;
271         GtkTextIter insert_iter;
272         
273         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (userdata));
274         g_return_if_fail (GTK_IS_TEXT_MARK (mark));
275         window = MODEST_MSG_EDIT_WINDOW (userdata);
276         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
277                 
278         insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
279         gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &insert_iter, insert_mark);
280         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &insert_iter, &location);
281         
282         if (priv->header_box)
283                 v_scroll_min_value += priv->header_box->allocation.height + DEFAULT_MAIN_VBOX_SPACING;
284         v_scroll_min_value += location.y;
285         v_scroll_max_value = v_scroll_min_value + location.height;
286         
287         v_scroll_visible = GTK_WIDGET (window)->allocation.height;
288         
289         vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll));
290         
291         if (((gdouble) v_scroll_min_value) < vadj->value)
292                 gtk_adjustment_set_value (vadj, v_scroll_min_value);
293         else if (((gdouble) v_scroll_max_value) > (vadj->value + vadj->page_size))
294                 gtk_adjustment_set_value (vadj, ((gdouble)v_scroll_max_value) - vadj->page_size);
295 }
296
297 static void
298 init_window (ModestMsgEditWindow *obj)
299 {
300         GtkWidget *from_caption, *to_caption, *subject_caption;
301         GtkWidget *main_vbox;
302         ModestMsgEditWindowPrivate *priv;
303         ModestPairList *protos;
304         GtkSizeGroup *size_group;
305
306         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
307
308         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
309
310         protos = get_transports ();
311         priv->from_field    = modest_combo_box_new (protos, g_str_equal);
312         modest_pair_list_free (protos);
313
314         priv->to_field      = gtk_entry_new_with_max_length (80);
315         g_object_set (G_OBJECT (priv->to_field), "autocap", FALSE, NULL);
316         priv->cc_field      = gtk_entry_new_with_max_length (80);
317         g_object_set (G_OBJECT (priv->cc_field), "autocap", FALSE, NULL);
318         priv->bcc_field     = gtk_entry_new_with_max_length (80);
319         g_object_set (G_OBJECT (priv->bcc_field), "autocap", FALSE, NULL);
320         priv->subject_field = gtk_entry_new_with_max_length (80);
321         g_object_set (G_OBJECT (priv->subject_field), "autocap", TRUE, NULL);
322         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field), SUBJECT_MAX_LENGTH);
323         
324         priv->header_box = gtk_vbox_new (FALSE, 0);
325         
326         from_caption = hildon_caption_new (size_group, _("From:"), priv->from_field, NULL, 0);
327         to_caption = hildon_caption_new (size_group, _("To:"), priv->to_field, NULL, 0);
328         priv->cc_caption = hildon_caption_new (size_group, _("Cc:"), priv->cc_field, NULL, 0);
329         priv->bcc_caption = hildon_caption_new (size_group, _("Bcc:"), priv->bcc_field, NULL, 0);
330         subject_caption = hildon_caption_new (size_group, _("Subject:"), priv->subject_field, NULL, 0);
331
332         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
333         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
334         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
335         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
336         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
337
338
339         priv->msg_body = wp_text_view_new ();
340         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
341         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
342         g_object_set (priv->text_buffer, "font_scale", 1.0, NULL);
343         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
344 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
345         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
346         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
347                           G_CALLBACK (text_buffer_refresh_attributes), obj);
348         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
349                           G_CALLBACK (text_buffer_mark_set), obj);
350         g_signal_connect (G_OBJECT (obj), "window-state-event",
351                           G_CALLBACK (modest_msg_edit_window_window_state_event),
352                           NULL);
353
354         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
355         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
356         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SCROLL_NONE);
357         
358         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
359
360         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
361         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
362
363         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
364         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
365         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
366         
367         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL))
368                 gtk_widget_hide (priv->cc_field);
369         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL))
370                 gtk_widget_hide (priv->bcc_field);
371
372         gtk_container_add (GTK_CONTAINER(obj), priv->scroll);
373 }
374         
375
376
377 static void
378 modest_msg_edit_window_finalize (GObject *obj)
379 {
380         G_OBJECT_CLASS(parent_class)->finalize (obj);
381 }
382
383
384
385 static gboolean
386 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMsgEditWindow *self)
387 {
388         save_settings (self);
389         return FALSE;
390 }
391
392 static GtkWidget *
393 menubar_to_menu (GtkUIManager *ui_manager)
394 {
395         GtkWidget *main_menu;
396         GtkWidget *menubar;
397         GList *iter;
398
399         /* Create new main menu */
400         main_menu = gtk_menu_new();
401
402         /* Get the menubar from the UI manager */
403         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
404
405         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
406         while (iter) {
407                 GtkWidget *menu;
408
409                 menu = GTK_WIDGET (iter->data);
410                 gtk_widget_reparent(menu, main_menu);
411
412                 iter = g_list_next (iter);
413         }
414         return main_menu;
415 }
416
417
418 static void
419 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
420 {
421         TnyHeader *header;
422         const gchar *to, *cc, *bcc, *subject, *body;
423         ModestMsgEditWindowPrivate *priv;
424         
425         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
426         g_return_if_fail (TNY_IS_MSG (msg));
427
428         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
429
430         header = tny_msg_get_header (msg);
431         to      = tny_header_get_to (header);
432         cc      = tny_header_get_cc (header);
433         bcc     = tny_header_get_bcc (header);
434         subject = tny_header_get_subject (header);
435
436         if (to)
437                 gtk_entry_set_text (GTK_ENTRY(priv->to_field),  to);
438         if (cc)
439                 gtk_entry_set_text (GTK_ENTRY(priv->cc_field),  cc);
440         if (bcc)
441                 gtk_entry_set_text (GTK_ENTRY(priv->bcc_field), bcc);
442         if (subject)
443                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);   
444
445 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
446         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
447         body = modest_tny_msg_get_body (msg, FALSE);
448         if ((body!=NULL) && (body[0] != '\0')) {
449                 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
450                 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
451                                                     (gchar *) body,
452                                                     -1);
453                 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
454         } else {
455                 WPTextBufferFormat fmt = {0};
456
457                 fmt.font_size = DEFAULT_FONT_SIZE;
458                 fmt.font = DEFAULT_FONT;
459                 fmt.rich_text = 1;
460                 fmt.text_position = TEXT_POSITION_NORMAL;
461                 fmt.justification = 0;
462                 fmt.cs.font_size = 1;
463                 fmt.cs.font = 1;
464                 fmt.cs.text_position = 1;
465                 fmt.cs.justification = 1;
466                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &fmt);
467         }
468
469         if (!to) {
470                 gtk_widget_grab_focus (priv->to_field);
471         } else {
472                 gtk_widget_grab_focus (priv->msg_body);
473         }
474
475         /* TODO: lower priority, select in the From: combo to the
476            value that comes from msg <- not sure, should it be
477            allowed? */
478         
479         /* TODO: set attachments */
480 }
481
482 static void
483 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
484 {
485         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
486         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
487         GtkWidget *font_placeholder;
488         GtkWidget *tool_item;
489         gint insert_index;
490         gint size_index;
491         gint font_index;
492
493         /* Toolbar */
494         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
495         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
496
497         /* should we hide the toolbar? */
498         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
499                 gtk_widget_hide (parent_priv->toolbar);
500
501         /* Font management toolbar elements */
502         font_placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
503         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(font_placeholder));
504
505         /* font color */
506         tool_item = GTK_WIDGET (gtk_tool_item_new ());
507         priv->font_color_button = hildon_color_button_new ();
508         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
509         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
510         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
511
512         /* font_size */
513         priv->size_combobox = gtk_combo_box_new_text ();
514         gtk_widget_set_size_request (priv->size_combobox, DEFAULT_SIZE_COMBOBOX_WIDTH, -1);
515         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
516                 gchar size_text[5];
517                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
518                 gtk_combo_box_append_text (GTK_COMBO_BOX (priv->size_combobox), size_text);
519         }
520         gtk_combo_box_set_active (GTK_COMBO_BOX (priv->size_combobox), wp_get_font_size_index(12, 4));
521         tool_item = GTK_WIDGET (gtk_tool_item_new ());
522         gtk_container_add (GTK_CONTAINER (tool_item), priv->size_combobox);
523         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
524         g_signal_connect_swapped (G_OBJECT (priv->size_combobox), "changed", G_CALLBACK (modest_msg_edit_window_size_combobox_change), window);
525
526         priv->font_combobox = gtk_combo_box_new_text ();
527         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
528                 gtk_combo_box_append_text (GTK_COMBO_BOX (priv->font_combobox), wp_get_font_name (font_index));
529         }
530         tool_item = GTK_WIDGET (gtk_tool_item_new ());
531         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_combobox);
532         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
533         g_signal_connect_swapped (G_OBJECT (priv->font_combobox), "changed", G_CALLBACK (modest_msg_edit_window_font_combobox_change), window);
534 }
535
536
537
538 ModestWindow*
539 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
540 {
541         GObject *obj;
542         ModestWindowPrivate *parent_priv;
543         ModestMsgEditWindowPrivate *priv;
544         GtkActionGroup *action_group;
545         GError *error = NULL;
546
547         g_return_val_if_fail (msg, NULL);
548         
549         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
550
551         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
552         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
553
554         parent_priv->ui_manager = gtk_ui_manager_new();
555         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
556
557         /* Add common actions */
558         gtk_action_group_add_actions (action_group,
559                                       modest_msg_edit_action_entries,
560                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
561                                       obj);
562         gtk_action_group_add_toggle_actions (action_group,
563                                              modest_msg_edit_toggle_action_entries,
564                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
565                                              obj);
566         gtk_action_group_add_radio_actions (action_group,
567                                             modest_msg_edit_alignment_radio_action_entries,
568                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
569                                             GTK_JUSTIFY_LEFT,
570                                             G_CALLBACK (modest_ui_actions_on_change_justify),
571                                             obj);
572         gtk_action_group_add_radio_actions (action_group,
573                                             modest_msg_edit_zoom_action_entries,
574                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
575                                             100,
576                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
577                                             obj);
578         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
579         g_object_unref (action_group);
580
581         /* Load the UI definition */
582         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml", &error);
583         if (error != NULL) {
584                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
585                 g_error_free (error);
586                 error = NULL;
587         }
588
589         /* Add accelerators */
590         gtk_window_add_accel_group (GTK_WINDOW (obj), 
591                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
592
593         /* Menubar */
594         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
595         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
596
597         /* Init window */
598         init_window (MODEST_MSG_EDIT_WINDOW(obj));
599
600         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
601                 
602         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
603         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
604
605         g_signal_connect (G_OBJECT(obj), "delete-event",
606                           G_CALLBACK(on_delete_event), obj);
607
608         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
609
610         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
611
612         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
613
614         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
615         
616         return (ModestWindow*)obj;
617 }
618
619 static gint
620 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
621 {
622         GString **string_buffer = (GString **) user_data;
623
624         *string_buffer = g_string_append (*string_buffer, buffer);
625    
626         return 0;
627 }
628
629 static gchar *
630 get_formatted_data (ModestMsgEditWindow *edit_window)
631 {
632         ModestMsgEditWindowPrivate *priv;
633         GString *string_buffer = g_string_new ("");
634         
635         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
636
637         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
638
639         return g_string_free (string_buffer, FALSE);
640                                                                         
641 }
642
643 MsgData * 
644 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
645 {
646         MsgData *data;
647         const gchar *account_name;
648         GtkTextBuffer *buf;
649         GtkTextIter b, e;
650         ModestMsgEditWindowPrivate *priv;
651         
652         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
653
654         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
655                                                                         
656         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
657         g_return_val_if_fail (account_name, NULL);
658         
659         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));        
660         gtk_text_buffer_get_bounds (buf, &b, &e);
661         
662         /* don't free these (except from) */
663         data = g_slice_new0 (MsgData);
664         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
665                                                              account_name);
666         data->to      =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->to_field));
667         data->cc      =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->cc_field));
668         data->bcc     =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->bcc_field));
669         data->subject =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field));  
670         data->plain_body =  (gchar *) gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE);
671         data->html_body  =  get_formatted_data (edit_window);
672         data->attachments = priv->attachments;
673
674         return data;
675 }
676
677 void 
678 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
679                                                       MsgData *data)
680 {
681         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
682
683         g_free (data->from);
684         g_free (data->html_body);
685         g_free (data->plain_body);
686         g_slice_free (MsgData, data);
687 }
688
689 ModestMsgEditFormat
690 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
691 {
692         gboolean rich_text;
693         ModestMsgEditWindowPrivate *priv = NULL;
694         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
695
696         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
697
698         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
699         if (rich_text)
700                 return MODEST_MSG_EDIT_FORMAT_HTML;
701         else
702                 return MODEST_MSG_EDIT_FORMAT_TEXT;
703 }
704
705 void
706 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
707                                    ModestMsgEditFormat format)
708 {
709         ModestMsgEditWindowPrivate *priv;
710
711         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
712         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
713
714         switch (format) {
715         case MODEST_MSG_EDIT_FORMAT_HTML:
716                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
717                 break;
718         case MODEST_MSG_EDIT_FORMAT_TEXT:
719                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
720                 break;
721         default:
722                 g_return_if_reached ();
723         }
724 }
725
726 ModestMsgEditFormatState *
727 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
728 {
729         ModestMsgEditFormatState *format_state = NULL;
730         ModestMsgEditWindowPrivate *priv;
731         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
732
733         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
734         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
735
736         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
737
738         format_state = g_new0 (ModestMsgEditFormatState, 1);
739         format_state->bold = buffer_format->bold&0x1;
740         format_state->italics = buffer_format->italic&0x1;
741         format_state->bullet = buffer_format->bullet&0x1;
742         format_state->color = buffer_format->color;
743         format_state->font_size = buffer_format->font_size;
744         format_state->font_family = wp_get_font_name (buffer_format->font);
745         format_state->justification = buffer_format->justification;
746         g_free (buffer_format);
747
748         return format_state;
749  
750 }
751
752 void
753 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
754                                          const ModestMsgEditFormatState *format_state)
755 {
756         ModestMsgEditWindowPrivate *priv;
757         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
758         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
759         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
760         g_return_if_fail (format_state != NULL);
761
762         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
763         gtk_widget_grab_focus (priv->msg_body);
764         buffer_format->bold = (format_state->bold != FALSE);
765         buffer_format->italic = (format_state->italics != FALSE);
766         buffer_format->color = format_state->color;
767         buffer_format->font_size = format_state->font_size;
768         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
769         buffer_format->justification = format_state->justification;
770         buffer_format->bullet = format_state->bullet;
771
772         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
773
774         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
775         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
776         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
777         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
778         buffer_format->cs.font = (buffer_format->font != current_format->font);
779         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
780         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
781
782         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
783         if (buffer_format->cs.bold) {
784                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
785         }
786         if (buffer_format->cs.italic) {
787                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
788         }
789         if (buffer_format->cs.color) {
790                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
791         }
792         if (buffer_format->cs.font_size) {
793                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
794         }
795         if (buffer_format->cs.justification) {
796                 switch (buffer_format->justification) {
797                 case GTK_JUSTIFY_LEFT:
798                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
799                         break;
800                 case GTK_JUSTIFY_CENTER:
801                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
802                         break;
803                 case GTK_JUSTIFY_RIGHT:
804                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
805                         break;
806                 default:
807                         break;
808                 }
809                         
810         }
811         if (buffer_format->cs.font) {
812                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
813         }
814         if (buffer_format->cs.bullet) {
815                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet));
816         }
817 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
818         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
819
820         g_free (current_format);
821
822 }
823
824 static void
825 toggle_action_set_active_block_notify (GtkToggleAction *action,
826                                        gboolean value)
827 {
828         GSList *proxies = NULL;
829
830         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
831              proxies != NULL; proxies = g_slist_next (proxies)) {
832                 GtkWidget *widget = (GtkWidget *) proxies->data;
833                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
834         }
835
836         gtk_toggle_action_set_active (action, value);
837
838         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
839              proxies != NULL; proxies = g_slist_next (proxies)) {
840                 GtkWidget *widget = (GtkWidget *) proxies->data;
841                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
842         }
843 }
844
845 static void
846 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
847 {
848         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
849         GtkAction *action;
850         ModestWindowPrivate *parent_priv;
851         ModestMsgEditWindowPrivate *priv;
852         
853         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
854         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
855
856         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
857         
858         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
859         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
860
861         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
862         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
863
864         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBulletedList");
865         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
866
867         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
868                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
869                                          window);
870         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
871         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
872                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
873                                            window);
874
875         g_signal_handlers_block_by_func (G_OBJECT (priv->size_combobox), 
876                                          G_CALLBACK (modest_msg_edit_window_size_combobox_change),
877                                          window);
878         gtk_combo_box_set_active (GTK_COMBO_BOX (priv->size_combobox), buffer_format->font_size);
879         g_signal_handlers_unblock_by_func (G_OBJECT (priv->size_combobox), 
880                                            G_CALLBACK (modest_msg_edit_window_size_combobox_change),
881                                            window);
882
883         g_signal_handlers_block_by_func (G_OBJECT (priv->font_combobox), 
884                                          G_CALLBACK (modest_msg_edit_window_font_combobox_change),
885                                          window);
886         gtk_combo_box_set_active (GTK_COMBO_BOX (priv->font_combobox), buffer_format->font);
887         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_combobox), 
888                                            G_CALLBACK (modest_msg_edit_window_font_combobox_change),
889                                            window);
890
891         g_free (buffer_format);
892
893 }
894
895 void
896 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
897 {
898         
899         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
900         ModestMsgEditWindowPrivate *priv;
901         GtkWidget *dialog = NULL;
902         gint response;
903         const GdkColor *new_color = NULL;
904         
905         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
906         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
907         
908         dialog = hildon_color_selector_new (GTK_WINDOW (window));
909         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), & (buffer_format->color));
910         g_free (buffer_format);
911
912         response = gtk_dialog_run (GTK_DIALOG (dialog));
913         switch (response) {
914         case GTK_RESPONSE_OK:
915                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
916                 break;
917         default:
918                 break;
919         }
920         gtk_widget_destroy (dialog);
921
922         if (new_color != NULL)
923                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
924
925 }
926
927 void
928 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
929 {
930         
931         ModestMsgEditWindowPrivate *priv;
932         GtkWidget *dialog = NULL;
933         gint response;
934         const GdkColor *old_color = NULL;
935         const GdkColor *new_color = NULL;
936         
937         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
938         old_color = wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
939         
940         dialog = hildon_color_selector_new (GTK_WINDOW (window));
941         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), (GdkColor *) old_color);
942
943         response = gtk_dialog_run (GTK_DIALOG (dialog));
944         switch (response) {
945         case GTK_RESPONSE_OK:
946                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
947                 break;
948         default:
949                 break;
950         }
951         gtk_widget_destroy (dialog);
952
953         if (new_color != NULL)
954                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
955
956 }
957
958 void
959 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
960 {
961         
962         ModestMsgEditWindowPrivate *priv;
963         GtkWidget *dialog = NULL;
964         gint response = 0;
965         gchar *filename = NULL;
966         
967         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
968         
969         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
970
971         response = gtk_dialog_run (GTK_DIALOG (dialog));
972         switch (response) {
973         case GTK_RESPONSE_OK:
974                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
975                 break;
976         default:
977                 break;
978         }
979         gtk_widget_destroy (dialog);
980
981         if (filename) {
982                 GdkPixbuf *pixbuf = NULL;
983                 GtkTextIter position;
984                 GtkTextMark *insert_mark;
985
986                 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
987                 if (pixbuf) {
988                         gint image_file_id;
989                         GdkPixbufFormat *pixbuf_format;
990
991                         image_file_id = g_open (filename, O_RDONLY, 0);
992                         pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
993                         if ((image_file_id != -1)&&(pixbuf_format != NULL)) {
994                                 TnyMimePart *image_part;
995                                 TnyStream *image_stream;
996                                 gchar **mime_types;
997                                 gchar *mime_type;
998                                 gchar *basename;
999                                 gchar *content_id;
1000
1001                                 mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format);
1002                                 if ((mime_types != NULL) && (mime_types[0] != NULL)) {
1003                                         mime_type = mime_types[0];
1004                                 } else {
1005                                         mime_type = "image/unknown";
1006                                 }
1007                                 image_part = tny_platform_factory_new_mime_part
1008                                         (modest_runtime_get_platform_factory ());
1009                                 image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id));
1010
1011                                 tny_mime_part_construct_from_stream (image_part, image_stream, mime_type);
1012                                 g_strfreev (mime_types);
1013
1014                                 content_id = g_strdup_printf ("%d", priv->last_cid);
1015                                 tny_mime_part_set_content_id (image_part, content_id);
1016                                 g_free (content_id);
1017                                 priv->last_cid++;
1018
1019                                 basename = g_path_get_basename (filename);
1020                                 tny_mime_part_set_filename (image_part, basename);
1021                                 g_free (basename);
1022                                 
1023                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1024                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1025                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf);
1026                                 priv->attachments = g_list_prepend (priv->attachments, image_part);
1027                         } else if (image_file_id == -1) {
1028                                 close (image_file_id);
1029                         }
1030                 }
1031         }
1032
1033
1034 }
1035
1036 static void
1037 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1038                                             gpointer userdata)
1039 {
1040         ModestMsgEditWindowPrivate *priv;
1041         GdkColor *new_color;
1042
1043         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1044         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1045
1046         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1047         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1048
1049 }
1050
1051 static void
1052 modest_msg_edit_window_size_combobox_change (ModestMsgEditWindow *window,
1053                                              gpointer userdata)
1054 {
1055         ModestMsgEditWindowPrivate *priv;
1056         gint new_size_index;
1057
1058         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1059         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1060
1061         new_size_index = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->size_combobox));
1062
1063         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) new_size_index))
1064                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1065
1066         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));;
1067 }
1068
1069 static void
1070 modest_msg_edit_window_font_combobox_change (ModestMsgEditWindow *window,
1071                                              gpointer userdata)
1072 {
1073         ModestMsgEditWindowPrivate *priv;
1074         gint new_font_index;
1075
1076         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1077         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1078
1079         new_font_index = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->font_combobox));
1080
1081         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) new_font_index))
1082                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1083
1084         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1085 }
1086
1087 static void
1088 modest_msg_edit_window_set_zoom (ModestWindow *window,
1089                                  gdouble zoom)
1090 {
1091         ModestMsgEditWindowPrivate *priv;
1092      
1093         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1094
1095         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1096         priv->zoom_level = zoom;
1097         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1098 }
1099
1100 static gdouble
1101 modest_msg_edit_window_get_zoom (ModestWindow *window)
1102 {
1103         ModestMsgEditWindowPrivate *priv;
1104      
1105         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1106
1107         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1108         return priv->zoom_level;
1109 }
1110
1111 static gboolean
1112 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1113 {
1114         ModestWindowPrivate *parent_priv;
1115         GtkRadioAction *zoom_radio_action;
1116         GSList *group, *node;
1117
1118         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1119         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1120                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1121
1122         group = gtk_radio_action_get_group (zoom_radio_action);
1123
1124         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1125                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_max_zoom_level"));
1126                 return FALSE;
1127         }
1128
1129         for (node = group; node != NULL; node = g_slist_next (node)) {
1130                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1131                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1132                         return TRUE;
1133                 }
1134         }
1135         return FALSE;
1136 }
1137
1138 static gboolean
1139 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1140 {
1141         ModestWindowPrivate *parent_priv;
1142         GtkRadioAction *zoom_radio_action;
1143         GSList *group, *node;
1144
1145         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1146         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1147                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1148
1149         group = gtk_radio_action_get_group (zoom_radio_action);
1150
1151         for (node = group; node != NULL; node = g_slist_next (node)) {
1152                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1153                         if (node->next != NULL) {
1154                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1155                                 return TRUE;
1156                         } else
1157                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_min_zoom_level"));
1158                         break;
1159                 }
1160         }
1161         return FALSE;
1162 }
1163
1164 static gboolean
1165 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1166 {
1167         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1168                 ModestWindowPrivate *parent_priv;
1169                 ModestWindowMgr *mgr;
1170                 gboolean is_fullscreen;
1171                 GtkAction *fs_toggle_action;
1172                 gboolean active;
1173
1174                 mgr = modest_runtime_get_window_mgr ();
1175                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1176
1177                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1178                 
1179                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ShowToggleFullscreenMenu");
1180                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1181                 if (is_fullscreen != active)
1182                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1183         }
1184
1185         return FALSE;
1186
1187 }
1188
1189 void
1190 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1191 {
1192         ModestWindowPrivate *parent_priv;
1193         GtkAction *fs_toggle_action;
1194         gboolean active;
1195
1196         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1197
1198         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ShowToggleFullscreenMenu");
1199         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1200         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1201 }
1202
1203 void
1204 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1205                                 gboolean show)
1206 {
1207         ModestMsgEditWindowPrivate *priv = NULL;
1208         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1209
1210         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1211         if (show)
1212                 gtk_widget_show (priv->cc_caption);
1213         else
1214                 gtk_widget_hide (priv->cc_caption);
1215 }
1216
1217 void
1218 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1219                                  gboolean show)
1220 {
1221         ModestMsgEditWindowPrivate *priv = NULL;
1222         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1223
1224         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1225         if (show)
1226                 gtk_widget_show (priv->bcc_caption);
1227         else
1228                 gtk_widget_hide (priv->bcc_caption);
1229 }
1230