2007-06-07 Marcus Bauer <marcusb@openismus.com>
[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 #include <tny-vfs-stream.h>
38
39 #include <config.h>
40
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
43
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
48
49 #include <modest-runtime.h>
50
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-address-book.h"
59 #include "modest-text-utils.h"
60 #include <tny-simple-list.h>
61 #include <wptextview.h>
62 #include <wptextbuffer.h>
63 #include "modest-scroll-area.h"
64
65 #include "modest-hildon-includes.h"
66 #include "widgets/modest-msg-edit-window-ui.h"
67 #include <libgnomevfs/gnome-vfs-mime.h>
68
69
70 #define DEFAULT_FONT_SIZE 3
71 #define DEFAULT_FONT 2
72 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
73 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
74 #define DEFAULT_MAIN_VBOX_SPACING 6
75 #define SUBJECT_MAX_LENGTH 1000
76
77 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
78 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
79 static void  modest_msg_edit_window_finalize     (GObject *obj);
80
81 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
82 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
83 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
84 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
85 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
86 static void  reset_modified (ModestMsgEditWindow *editor);
87 static gboolean is_modified (ModestMsgEditWindow *editor);
88
89 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
90 static void  text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata);
91 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
92 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
93 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
94 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
95                                                          gpointer userdata);
96 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
97                                                  gpointer userdata);
98 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
99                                                  gpointer userdata);
100 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
101 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
102                                                            GdkEventWindowState *event, 
103                                                            gpointer userdata);
104 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
105                                                      ModestRecptEditor *editor);
106 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
107                                                            ModestMsgEditWindow *window);
108
109 /* ModestWindow methods implementation */
110 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
111 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
112 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
113 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
114 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
115                                                    gboolean show_toolbar);
116 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
117                                                            GdkEvent *event,
118                                                            ModestMsgEditWindow *window);
119 static void update_window_title (ModestMsgEditWindow *window);
120 static void update_dimmed (ModestMsgEditWindow *window);
121
122
123 /* list my signals */
124 enum {
125         /* MY_SIGNAL_1, */
126         /* MY_SIGNAL_2, */
127         LAST_SIGNAL
128 };
129
130 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
131 struct _ModestMsgEditWindowPrivate {
132         GtkWidget   *msg_body;
133         GtkWidget   *header_box;
134         
135         ModestPairList *from_field_protos;
136         GtkWidget   *from_field;
137         
138         GtkWidget   *to_field;
139         GtkWidget   *cc_field;
140         GtkWidget   *bcc_field;
141         GtkWidget   *subject_field;
142         GtkWidget   *attachments_view;
143         GtkWidget   *priority_icon;
144         GtkWidget   *add_attachment_button;
145
146         GtkWidget   *cc_caption;
147         GtkWidget   *bcc_caption;
148         GtkWidget   *attachments_caption;
149
150         GtkTextBuffer *text_buffer;
151
152         GtkWidget   *font_size_toolitem;
153         GtkWidget   *font_face_toolitem;
154         GtkWidget   *font_color_button;
155         GSList      *font_items_group;
156         GtkWidget   *font_tool_button_label;
157         GSList      *size_items_group;
158         GtkWidget   *size_tool_button_label;
159
160         GtkWidget   *scroll;
161
162         gint last_cid;
163         GList *attachments;
164
165         TnyHeaderFlags priority_flags;
166
167         gdouble zoom_level;
168         
169         gulong      clipboard_change_handler_id;
170
171         TnyMsg      *draft_msg;
172 };
173
174 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
175                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
176                                                     ModestMsgEditWindowPrivate))
177 /* globals */
178 static GtkWindowClass *parent_class = NULL;
179
180 /* uncomment the following if you have defined any signals */
181 /* static guint signals[LAST_SIGNAL] = {0}; */
182
183 GType
184 modest_msg_edit_window_get_type (void)
185 {
186         static GType my_type = 0;
187         if (!my_type) {
188                 static const GTypeInfo my_info = {
189                         sizeof(ModestMsgEditWindowClass),
190                         NULL,           /* base init */
191                         NULL,           /* base finalize */
192                         (GClassInitFunc) modest_msg_edit_window_class_init,
193                         NULL,           /* class finalize */
194                         NULL,           /* class data */
195                         sizeof(ModestMsgEditWindow),
196                         1,              /* n_preallocs */
197                         (GInstanceInitFunc) modest_msg_edit_window_init,
198                         NULL
199                 };
200                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
201                                                   "ModestMsgEditWindow",
202                                                   &my_info, 0);
203
204                 wp_text_buffer_library_init ();
205         }
206         return my_type;
207 }
208
209 static void
210 save_state (ModestWindow *self)
211 {
212         modest_widget_memory_save (modest_runtime_get_conf(),
213                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
214 }
215
216
217 static void
218 restore_settings (ModestMsgEditWindow *self)
219 {
220         modest_widget_memory_restore (modest_runtime_get_conf(),
221                                       G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
222 }
223
224
225 static void
226 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
227 {
228         GObjectClass *gobject_class;
229         ModestWindowClass *modest_window_class;
230         gobject_class = (GObjectClass*) klass;
231         modest_window_class = (ModestWindowClass*) klass;
232
233         parent_class            = g_type_class_peek_parent (klass);
234         gobject_class->finalize = modest_msg_edit_window_finalize;
235
236         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
237         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
238         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
239         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
240         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
241
242         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
243
244         modest_window_class->save_state_func = save_state;
245 }
246
247 static void
248 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
249 {
250         ModestMsgEditWindowPrivate *priv;
251         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
252
253         priv->msg_body      = NULL;
254         priv->from_field    = NULL;
255         priv->to_field      = NULL;
256         priv->cc_field      = NULL;
257         priv->bcc_field     = NULL;
258         priv->subject_field = NULL;
259         priv->attachments   = NULL;
260         priv->last_cid      = 0;
261         priv->zoom_level    = 1.0;
262
263         priv->cc_caption    = NULL;
264         priv->bcc_caption    = NULL;
265
266         priv->priority_flags = 0;
267
268         priv->draft_msg = NULL;
269         priv->clipboard_change_handler_id = 0;
270 }
271
272
273 /* FIXME: this is a dup from the one in gtk/ */
274
275 /** 
276  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
277  */
278 static ModestPairList*
279 get_transports (void)
280 {
281         GSList *transports = NULL;
282         
283         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
284         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
285                                                 TRUE /* only enabled accounts. */); 
286                                                 
287         GSList *cursor = accounts;
288         while (cursor) {
289                 const gchar *account_name = cursor->data;
290                 gchar *from_string  = NULL;
291                 if (account_name) {
292                         from_string = modest_account_mgr_get_from_string (account_mgr,
293                                                                           account_name);
294                 }
295                 
296                 if (from_string && account_name) {
297                         gchar *name = g_strdup (account_name);
298                         ModestPair *pair = modest_pair_new ((gpointer) name,
299                                                 (gpointer) from_string , TRUE);
300                         transports = g_slist_prepend (transports, pair);
301                 }
302                 
303                 cursor = cursor->next;
304         }
305         g_slist_free (accounts);
306         return transports;
307 }
308
309
310 static void
311 init_window (ModestMsgEditWindow *obj)
312 {
313         GtkWidget *from_caption, *to_caption, *subject_caption;
314         GtkWidget *main_vbox;
315         ModestMsgEditWindowPrivate *priv;
316
317         GtkSizeGroup *size_group;
318         GtkWidget *frame;
319         GtkWidget *scroll_area;
320         GtkWidget *subject_box;
321         GtkWidget *attachment_icon;
322
323         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
324
325         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
326
327         /* Note: This ModestPairList* must exist for as long as the combo
328          * that uses it, because the ModestComboBox uses the ID opaquely, 
329          * so it can't know how to manage its memory. */ 
330         priv->from_field_protos = get_transports ();
331
332         priv->from_field    = modest_combo_box_new (priv->from_field_protos, g_str_equal);
333
334         priv->to_field      = modest_recpt_editor_new ();
335         priv->cc_field      = modest_recpt_editor_new ();
336         priv->bcc_field     = modest_recpt_editor_new ();
337         subject_box = gtk_hbox_new (FALSE, 0);
338         priv->priority_icon = gtk_image_new ();
339         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
340         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
341         g_object_set (G_OBJECT (priv->subject_field), "hildon-input-mode", HILDON_GTK_INPUT_MODE_FULL, NULL);
342         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
343         priv->add_attachment_button = gtk_button_new ();
344         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
345         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
346         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
347         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
348         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
349         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
350         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
351         priv->attachments_view = modest_attachments_view_new (NULL);
352         
353         priv->header_box = gtk_vbox_new (FALSE, 0);
354         
355         from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
356         to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
357         priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
358         priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
359         subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
360         priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
361         g_object_unref (size_group);
362
363         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
364         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
365         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
366         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
367         gtk_size_group_add_widget (size_group, priv->subject_field);
368         gtk_size_group_add_widget (size_group, priv->attachments_view);
369         g_object_unref (size_group);
370
371         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
372         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
373         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
374         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
375         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
376         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
377         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
378
379
380         priv->msg_body = wp_text_view_new ();
381         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
382         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
383         g_object_set (priv->text_buffer, "font_scale", 1.0, NULL);
384         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
385 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
386         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
387
388         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
389                           G_CALLBACK (text_buffer_refresh_attributes), obj);
390         g_signal_connect (G_OBJECT (priv->text_buffer), "delete-range",
391                           G_CALLBACK (text_buffer_delete_range), obj);
392         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
393                           G_CALLBACK (text_buffer_can_undo), obj);
394         g_signal_connect (G_OBJECT (obj), "window-state-event",
395                           G_CALLBACK (modest_msg_edit_window_window_state_event),
396                           NULL);
397         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
398                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
399         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
400                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
401         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
402                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
403
404         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
405                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
406
407         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
408                           G_CALLBACK (msg_body_focus), obj);
409         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
410                           G_CALLBACK (msg_body_focus), obj);
411         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
412                           "changed", G_CALLBACK (recpt_field_changed), obj);
413         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
414                           "changed", G_CALLBACK (recpt_field_changed), obj);
415         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
416                           "changed", G_CALLBACK (recpt_field_changed), obj);
417         recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
418         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
419
420         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
421         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
422         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
423         
424         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
425
426         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
427         frame = gtk_frame_new (NULL);
428         gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
429
430         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
431         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
432         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
433         
434         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL)) {
435                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
436                 gtk_widget_hide (priv->cc_caption);
437         }
438         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL)) {
439                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
440                 gtk_widget_hide (priv->bcc_caption);
441         }
442
443         gtk_container_add (GTK_CONTAINER(obj), priv->scroll);
444         scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
445         gtk_container_add (GTK_CONTAINER (frame), scroll_area);
446         gtk_container_set_focus_vadjustment (GTK_CONTAINER (scroll_area), 
447                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
448
449         priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
450                                                               G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
451 }
452         
453
454
455 static void
456 modest_msg_edit_window_finalize (GObject *obj)
457 {
458         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
459
460         
461         if (priv->clipboard_change_handler_id > 0) {
462                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), priv->clipboard_change_handler_id);
463                 priv->clipboard_change_handler_id = 0;
464         }
465         
466         /* This had to stay alive for as long as the combobox that used it: */
467         modest_pair_list_free (priv->from_field_protos);
468         
469         G_OBJECT_CLASS(parent_class)->finalize (obj);
470 }
471
472 static gboolean
473 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMsgEditWindow *self)
474 {
475         GtkWidget *close_dialog;
476         ModestMsgEditWindowPrivate *priv;
477         gint response;
478
479         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
480         modest_window_save_state (MODEST_WINDOW (self));
481         if (is_modified (self)) {
482                 close_dialog = hildon_note_new_confirmation (GTK_WINDOW (self), _("mcen_nc_no_email_message_modified_save_changes"));
483                 response = gtk_dialog_run (GTK_DIALOG (close_dialog));
484                 gtk_widget_destroy (close_dialog);
485
486                 if (response != GTK_RESPONSE_CANCEL) {
487                         modest_ui_actions_on_save_to_drafts (NULL, self);
488                 }
489         } 
490 /*      /\* remove old message from drafts *\/ */
491 /*      if (priv->draft_msg) { */
492 /*              TnyHeader *header = tny_msg_get_header (priv->draft_msg); */
493 /*              TnyAccount *account = modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(), */
494 /*                                                                                         account_name, */
495 /*                                                                                         TNY_ACCOUNT_TYPE_STORE); */
496 /*              TnyFolder *folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS); */
497 /*              g_return_val_if_fail (TNY_IS_HEADER (header), FALSE); */
498 /*              g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE); */
499 /*              tny_folder_remove_msg (folder, header, NULL); */
500 /*              g_object_unref (folder); */
501 /*              g_object_unref (header); */
502 /*              g_object_unref (priv->draft_msg); */
503 /*              priv->draft_msg = NULL; */
504 /*      } */
505         gtk_widget_destroy (GTK_WIDGET (self));
506         
507         return TRUE;
508 }
509
510 static GtkWidget *
511 menubar_to_menu (GtkUIManager *ui_manager)
512 {
513         GtkWidget *main_menu;
514         GtkWidget *menubar;
515         GList *iter;
516
517         /* Create new main menu */
518         main_menu = gtk_menu_new();
519
520         /* Get the menubar from the UI manager */
521         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
522
523         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
524         while (iter) {
525                 GtkWidget *menu;
526
527                 menu = GTK_WIDGET (iter->data);
528                 gtk_widget_reparent(menu, main_menu);
529
530                 iter = g_list_next (iter);
531         }
532         return main_menu;
533 }
534
535
536 static void
537 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
538 {
539         TnyHeader *header;
540         const gchar *to, *cc, *bcc, *subject;
541         gchar *body;
542         ModestMsgEditWindowPrivate *priv;
543         GtkTextIter iter;
544         
545         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
546         g_return_if_fail (TNY_IS_MSG (msg));
547
548         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
549
550         header = tny_msg_get_header (msg);
551         to      = tny_header_get_to (header);
552         cc      = tny_header_get_cc (header);
553         bcc     = tny_header_get_bcc (header);
554         subject = tny_header_get_subject (header);
555
556         if (to)
557                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
558         if (cc)
559                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
560         if (bcc)
561                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
562         if (subject)
563                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
564
565         update_window_title (self);
566
567 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
568         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
569         body = modest_tny_msg_get_body (msg, TRUE);
570
571         if ((body == NULL)||(body[0] == '\0')) {
572                 g_free (body);
573                 body = modest_text_utils_convert_to_html ("");
574         }
575         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
576         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
577                                             (gchar *) body,
578                                             strlen (body));
579         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
580         g_free (body);
581
582         /* Get the default format required from configuration */
583         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
584                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
585         }
586
587         /* Set the default focus depending on having already a To: field or not */
588         if ((!to)||(*to == '\0')) {
589                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
590         } else {
591                 gtk_widget_grab_focus (priv->msg_body);
592         }
593
594         /* TODO: lower priority, select in the From: combo to the
595            value that comes from msg <- not sure, should it be
596            allowed? */
597         
598         /* Add attachments to the view */
599         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
600         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
601         if (priv->attachments == NULL) {
602                 gtk_widget_hide (priv->attachments_caption);
603         } else {
604                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
605                 gtk_widget_show_all (priv->attachments_caption);
606         }
607
608         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
609         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
610
611         reset_modified (self);
612
613         update_dimmed (self);
614         text_buffer_can_undo (priv->text_buffer, FALSE, self);
615
616         priv->draft_msg = msg;
617 }
618
619 static void
620 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
621                                 gpointer data)
622 {
623         GList *item_children, *node;
624         GtkWidget *bin_child;
625
626         bin_child = gtk_bin_get_child (GTK_BIN(item));
627
628         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
629         
630         for (node = item_children; node != NULL; node = g_list_next (node)) {
631                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
632                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
633                 }
634         }
635         g_list_free (item_children);
636 }
637
638 static void
639 menu_tool_button_dont_expand (GtkMenuToolButton *item)
640 {
641         GtkWidget *box;
642         GList *item_children, *node;
643
644         box = gtk_bin_get_child (GTK_BIN (item));
645         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
646         item_children = gtk_container_get_children (GTK_CONTAINER (box));
647         
648         for (node = item_children; node != NULL; node = g_list_next (node)) {
649                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
650                 if (GTK_IS_TOGGLE_BUTTON (node->data))
651                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
652                 else if (GTK_IS_BUTTON (node->data))
653                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
654         }
655         g_list_free (item_children);
656 }
657
658
659 static void
660 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
661 {
662         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
663         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
664         GtkWidget *placeholder;
665         GtkWidget *tool_item;
666         gint insert_index;
667         gchar size_text[5];
668         gint size_index;
669         gint font_index;
670         GtkWidget *sizes_menu;
671         GtkWidget *fonts_menu;
672         GSList *radio_group = NULL;
673         GSList *node = NULL;
674         gchar *markup;
675
676         /* Toolbar */
677         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
678         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
679
680         /* should we hide the toolbar? */
681         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
682                 gtk_widget_hide (parent_priv->toolbar);
683
684         /* Font color placeholder */
685         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
686         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
687
688         /* font color */
689         tool_item = GTK_WIDGET (gtk_tool_item_new ());
690         priv->font_color_button = hildon_color_button_new ();
691         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
692         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
693         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
694         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
695         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
696         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
697         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
698
699         /* Font size and face placeholder */
700         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
701         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
702         /* font_size */
703         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
704         priv->size_tool_button_label = gtk_label_new (NULL);
705         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
706         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
707                               size_text,"</span>", NULL);
708         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
709         g_free (markup);
710         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
711         sizes_menu = gtk_menu_new ();
712         priv->size_items_group = NULL;
713         radio_group = NULL;
714         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
715                 GtkWidget *size_menu_item;
716
717                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
718                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
719                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
720                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
721                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
722                 gtk_widget_show (size_menu_item);
723
724                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
725                         
726         }
727
728         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
729                 GtkWidget *item = (GtkWidget *) node->data;
730                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
731                                   window);
732         }
733
734         priv->size_items_group = g_slist_reverse (priv->size_items_group);
735         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
736         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
737         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
738         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
739         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
740         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
741         priv->font_size_toolitem = tool_item;
742
743         /* font face */
744         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
745         priv->font_tool_button_label = gtk_label_new (NULL);
746         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
747         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
748         g_free(markup);
749         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
750         fonts_menu = gtk_menu_new ();
751         priv->font_items_group = NULL;
752         radio_group = NULL;
753         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
754                 GtkWidget *font_menu_item;
755                 GtkWidget *child_label;
756
757                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
758                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
759                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
760                                       wp_get_font_name (font_index), "</span>", NULL);
761                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
762                 g_free (markup);
763                 
764                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
765                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
766                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
767                 gtk_widget_show (font_menu_item);
768
769                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
770                         
771         }
772         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
773                 GtkWidget *item = (GtkWidget *) node->data;
774                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
775                                   window);
776         }
777         priv->font_items_group = g_slist_reverse (priv->font_items_group);
778         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
779         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
780         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
781         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
782         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
783         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
784         priv->font_face_toolitem = tool_item;
785
786         /* Set expand and homogeneous for remaining items */
787         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
788         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
789         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
790         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
791         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
792         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
793         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
794         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
795         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
796
797
798 }
799
800
801
802 ModestWindow*
803 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
804 {
805         GObject *obj;
806         ModestWindowPrivate *parent_priv;
807         ModestMsgEditWindowPrivate *priv;
808         GtkActionGroup *action_group;
809         GError *error = NULL;
810         GdkPixbuf *window_icon = NULL;
811         GtkAction *action;
812         ModestConf *conf;
813         gboolean prefer_formatted;
814         gint file_format;
815
816         g_return_val_if_fail (msg, NULL);
817         
818         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
819
820         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
821         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
822
823         parent_priv->ui_manager = gtk_ui_manager_new();
824         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
825         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
826
827         /* Add common actions */
828         gtk_action_group_add_actions (action_group,
829                                       modest_msg_edit_action_entries,
830                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
831                                       obj);
832         gtk_action_group_add_toggle_actions (action_group,
833                                              modest_msg_edit_toggle_action_entries,
834                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
835                                              obj);
836         gtk_action_group_add_radio_actions (action_group,
837                                             modest_msg_edit_alignment_radio_action_entries,
838                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
839                                             GTK_JUSTIFY_LEFT,
840                                             G_CALLBACK (modest_ui_actions_on_change_justify),
841                                             obj);
842         gtk_action_group_add_radio_actions (action_group,
843                                             modest_msg_edit_zoom_action_entries,
844                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
845                                             100,
846                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
847                                             obj);
848         gtk_action_group_add_radio_actions (action_group,
849                                             modest_msg_edit_priority_action_entries,
850                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
851                                             0,
852                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
853                                             obj);
854         gtk_action_group_add_radio_actions (action_group,
855                                             modest_msg_edit_file_format_action_entries,
856                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
857                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
858                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
859                                             obj);
860         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
861         g_object_unref (action_group);
862
863         /* Load the UI definition */
864         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml", &error);
865         if (error != NULL) {
866                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
867                 g_clear_error (&error);
868         }
869
870         /* Add accelerators */
871         gtk_window_add_accel_group (GTK_WINDOW (obj), 
872                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
873
874         /* Menubar */
875         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
876         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
877
878         /* Init window */
879         init_window (MODEST_MSG_EDIT_WINDOW(obj));
880
881         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
882                 
883         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
884
885         g_signal_connect (G_OBJECT(obj), "delete-event",
886                           G_CALLBACK(on_delete_event), obj);
887
888         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
889
890         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
891
892         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
893
894         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
895
896         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
897
898         /* Set window icon */
899         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
900         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
901
902         /* Dim at start clipboard actions */
903         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
904         gtk_action_set_sensitive (action, FALSE);
905         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
906         gtk_action_set_sensitive (action, FALSE);
907
908         /* set initial state of cc and bcc */
909         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
910         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
911                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
912         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
913         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
914                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
915
916         /* Setup the file format */
917         conf = modest_runtime_get_conf ();
918         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
919         if (error) {
920                 g_clear_error (&error);
921                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
922         } else
923                 file_format = (prefer_formatted) ? 
924                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
925                         MODEST_FILE_FORMAT_PLAIN_TEXT;
926         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
927         
928         return (ModestWindow*) obj;
929 }
930
931 static gint
932 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
933 {
934         GString **string_buffer = (GString **) user_data;
935
936         *string_buffer = g_string_append (*string_buffer, buffer);
937    
938         return 0;
939 }
940
941 /**
942  * @result: A new string which should be freed with g_free().
943  */
944 static gchar *
945 get_formatted_data (ModestMsgEditWindow *edit_window)
946 {
947         ModestMsgEditWindowPrivate *priv;
948         GString *string_buffer = g_string_new ("");
949         
950         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
951
952         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
953
954         return g_string_free (string_buffer, FALSE);
955                                                                         
956 }
957
958 MsgData * 
959 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
960 {
961         MsgData *data;
962         const gchar *account_name;
963         ModestMsgEditWindowPrivate *priv;
964         
965         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
966
967         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
968                                                                         
969         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
970         g_return_val_if_fail (account_name, NULL);
971         
972         
973         /* don't free these (except from) */
974         data = g_slice_new0 (MsgData);
975         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
976                                                              account_name);
977         data->account_name = g_strdup (account_name);
978         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
979         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
980         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
981         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
982         if (priv->draft_msg) {
983                 data->draft_msg = g_object_ref (priv->draft_msg);
984         } else {
985                 data->draft_msg = NULL;
986         }
987
988         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
989         GtkTextIter b, e;
990         gtk_text_buffer_get_bounds (buf, &b, &e);
991         data->plain_body = g_strdup (gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE)); /* returns a copy */
992
993         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
994                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
995         else
996                 data->html_body = NULL;
997
998         data->attachments = priv->attachments; /* TODO: copy and free ? */
999         data->priority_flags = priv->priority_flags;
1000
1001         return data;
1002 }
1003
1004 /* TODO: We must duplicate this implementation for GNOME and Maemo, but that is unwise. */
1005 void 
1006 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1007                                                       MsgData *data)
1008 {
1009         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1010
1011         if (!data)
1012                 return;
1013
1014         g_free (data->to);
1015         g_free (data->cc);
1016         g_free (data->bcc);
1017         g_free (data->subject);
1018         g_free (data->plain_body);
1019         g_free (data->html_body);
1020         if (data->draft_msg != NULL) {
1021                 g_object_unref (data->draft_msg);
1022                 data->draft_msg = NULL;
1023         }
1024         g_free (data->account_name);
1025
1026         /* TODO: Free data->attachments? */
1027
1028         g_slice_free (MsgData, data);
1029 }
1030
1031 ModestMsgEditFormat
1032 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1033 {
1034         gboolean rich_text;
1035         ModestMsgEditWindowPrivate *priv = NULL;
1036         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1037
1038         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1039
1040         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1041         if (rich_text)
1042                 return MODEST_MSG_EDIT_FORMAT_HTML;
1043         else
1044                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1045 }
1046
1047 void
1048 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1049                                    ModestMsgEditFormat format)
1050 {
1051         ModestMsgEditWindowPrivate *priv;
1052
1053         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1054         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1055
1056         switch (format) {
1057         case MODEST_MSG_EDIT_FORMAT_HTML:
1058                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1059                 break;
1060         case MODEST_MSG_EDIT_FORMAT_TEXT:
1061                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1062                 break;
1063         default:
1064                 g_return_if_reached ();
1065         }
1066 }
1067
1068 ModestMsgEditFormatState *
1069 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1070 {
1071         ModestMsgEditFormatState *format_state = NULL;
1072         ModestMsgEditWindowPrivate *priv;
1073         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1074
1075         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1076         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1077
1078         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1079
1080         format_state = g_new0 (ModestMsgEditFormatState, 1);
1081         format_state->bold = buffer_format->bold&0x1;
1082         format_state->italics = buffer_format->italic&0x1;
1083         format_state->bullet = buffer_format->bullet&0x1;
1084         format_state->color = buffer_format->color;
1085         format_state->font_size = buffer_format->font_size;
1086         format_state->font_family = wp_get_font_name (buffer_format->font);
1087         format_state->justification = buffer_format->justification;
1088         g_free (buffer_format);
1089
1090         return format_state;
1091  
1092 }
1093
1094 void
1095 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1096                                          const ModestMsgEditFormatState *format_state)
1097 {
1098         ModestMsgEditWindowPrivate *priv;
1099         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1100         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1101         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1102         g_return_if_fail (format_state != NULL);
1103
1104         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1105         gtk_widget_grab_focus (priv->msg_body);
1106         buffer_format->bold = (format_state->bold != FALSE);
1107         buffer_format->italic = (format_state->italics != FALSE);
1108         buffer_format->color = format_state->color;
1109         buffer_format->font_size = format_state->font_size;
1110         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1111         buffer_format->justification = format_state->justification;
1112         buffer_format->bullet = format_state->bullet;
1113
1114         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1115
1116         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1117         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1118         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
1119         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1120         buffer_format->cs.font = (buffer_format->font != current_format->font);
1121         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1122         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1123
1124         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1125         if (buffer_format->cs.bold) {
1126                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1127         }
1128         if (buffer_format->cs.italic) {
1129                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1130         }
1131         if (buffer_format->cs.color) {
1132                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1133         }
1134         if (buffer_format->cs.font_size) {
1135                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
1136         }
1137         if (buffer_format->cs.justification) {
1138                 switch (buffer_format->justification) {
1139                 case GTK_JUSTIFY_LEFT:
1140                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1141                         break;
1142                 case GTK_JUSTIFY_CENTER:
1143                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1144                         break;
1145                 case GTK_JUSTIFY_RIGHT:
1146                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1147                         break;
1148                 default:
1149                         break;
1150                 }
1151                         
1152         }
1153         if (buffer_format->cs.font) {
1154                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
1155         }
1156         if (buffer_format->cs.bullet) {
1157                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet));
1158         }
1159 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1160         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1161
1162         g_free (current_format);
1163
1164 }
1165
1166 static void
1167 toggle_action_set_active_block_notify (GtkToggleAction *action,
1168                                        gboolean value)
1169 {
1170         GSList *proxies = NULL;
1171
1172         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1173              proxies != NULL; proxies = g_slist_next (proxies)) {
1174                 GtkWidget *widget = (GtkWidget *) proxies->data;
1175                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
1176         }
1177
1178         gtk_toggle_action_set_active (action, value);
1179
1180         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1181              proxies != NULL; proxies = g_slist_next (proxies)) {
1182                 GtkWidget *widget = (GtkWidget *) proxies->data;
1183                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
1184         }
1185 }
1186
1187 static void
1188 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1189 {
1190         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1191         GtkAction *action;
1192         ModestWindowPrivate *parent_priv;
1193         ModestMsgEditWindowPrivate *priv;
1194         GtkWidget *new_size_menuitem;
1195         GtkWidget *new_font_menuitem;
1196         
1197         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1198         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1199
1200         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1201                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1202                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1203                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1204         } else {
1205                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1206                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1207                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1208         }
1209
1210         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1211         
1212         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1213         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1214
1215         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1216         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1217
1218         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1219         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1220
1221         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1222                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1223                                          window);
1224         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1225         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1226                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1227                                            window);
1228
1229         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1230                                                       buffer_format->font_size))->data);
1231         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1232                 GtkWidget *label;
1233                 gchar *markup;
1234
1235                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1236                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1237                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1238                 g_free (markup);
1239                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1240                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1241                                                  window);
1242                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1243                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1244                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1245                                                    window);
1246         }
1247
1248         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1249                                                       buffer_format->font))->data);
1250         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1251                 GtkWidget *label;
1252                 gchar *markup;
1253
1254                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1255                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1256                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1257                 g_free (markup);
1258                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1259                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1260                                                  window);
1261                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1262                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1263                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1264                                                    window);
1265         }
1266
1267         g_free (buffer_format);
1268
1269 }
1270
1271
1272 void
1273 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1274 {
1275         
1276         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1277         ModestMsgEditWindowPrivate *priv;
1278         GtkWidget *dialog = NULL;
1279         gint response;
1280         const GdkColor *new_color = NULL;
1281         
1282         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1283         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1284         
1285 #ifdef MODEST_HILDON_VERSION_0  
1286         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1287         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1288 #else
1289         dialog = hildon_color_chooser_new ();
1290         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1291 #endif /*MODEST_HILDON_VERSION_0*/              
1292         g_free (buffer_format);
1293
1294         response = gtk_dialog_run (GTK_DIALOG (dialog));
1295         switch (response) {
1296         case GTK_RESPONSE_OK: {
1297 #ifdef MODEST_HILDON_VERSION_0
1298                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1299 #else
1300                 GdkColor col;
1301                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1302                 new_color = &col;
1303 #endif /*MODEST_HILDON_VERSION_0*/
1304         }
1305
1306         break;
1307         default:
1308                 break;
1309         }
1310         gtk_widget_destroy (dialog);
1311
1312         if (new_color != NULL)
1313                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1314
1315 }
1316
1317 void
1318 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1319 {
1320         
1321         ModestMsgEditWindowPrivate *priv;
1322         GtkWidget *dialog = NULL;
1323         gint response;
1324         GdkColor *old_color = NULL;
1325         const GdkColor *new_color = NULL;
1326         
1327         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1328         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1329         
1330 #ifdef MODEST_HILDON_VERSION_0  
1331         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1332         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1333 #else
1334         dialog = hildon_color_chooser_new ();
1335         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1336 #endif /*MODEST_HILDON_VERSION_9*/              
1337
1338         response = gtk_dialog_run (GTK_DIALOG (dialog));
1339         switch (response) {
1340         case GTK_RESPONSE_OK: {
1341 #ifdef MODEST_HILDON_VERSION_0
1342                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1343 #else
1344                 GdkColor col;
1345                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1346                 new_color = &col;
1347 #endif /*MODEST_HILDON_VERSION_0*/
1348           }
1349                 break;
1350         default:
1351                 break;
1352         }
1353         gtk_widget_destroy (dialog);
1354
1355         if (new_color != NULL)
1356                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1357
1358 }
1359
1360 void
1361 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1362 {
1363         
1364         ModestMsgEditWindowPrivate *priv;
1365         GtkWidget *dialog = NULL;
1366         gint response = 0;
1367         gchar *filename = NULL;
1368         
1369         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1370         
1371         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1372
1373         response = gtk_dialog_run (GTK_DIALOG (dialog));
1374         switch (response) {
1375         case GTK_RESPONSE_OK:
1376                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1377                 break;
1378         default:
1379                 break;
1380         }
1381         gtk_widget_destroy (dialog);
1382
1383         if (filename) {
1384                 GdkPixbuf *pixbuf = NULL;
1385                 GtkTextIter position;
1386                 GtkTextMark *insert_mark;
1387
1388                 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1389                 if (pixbuf) {
1390                         gint image_file_id;
1391                         GdkPixbufFormat *pixbuf_format;
1392
1393                         image_file_id = g_open (filename, O_RDONLY, 0);
1394                         pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
1395                         if ((image_file_id != -1)&&(pixbuf_format != NULL)) {
1396                                 TnyMimePart *image_part;
1397                                 TnyStream *image_stream;
1398                                 gchar **mime_types;
1399                                 gchar *mime_type;
1400                                 gchar *basename;
1401                                 gchar *content_id;
1402
1403                                 mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format);
1404                                 if ((mime_types != NULL) && (mime_types[0] != NULL)) {
1405                                         mime_type = mime_types[0];
1406                                 } else {
1407                                         mime_type = "image/unknown";
1408                                 }
1409                                 image_part = tny_platform_factory_new_mime_part
1410                                         (modest_runtime_get_platform_factory ());
1411                                 image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id));
1412
1413                                 tny_mime_part_construct_from_stream (image_part, image_stream, mime_type);
1414                                 g_strfreev (mime_types);
1415
1416                                 content_id = g_strdup_printf ("%d", priv->last_cid);
1417                                 tny_mime_part_set_content_id (image_part, content_id);
1418                                 g_free (content_id);
1419                                 priv->last_cid++;
1420
1421                                 basename = g_path_get_basename (filename);
1422                                 tny_mime_part_set_filename (image_part, basename);
1423                                 g_free (basename);
1424                                 
1425                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1426                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1427                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf);
1428                                 priv->attachments = g_list_prepend (priv->attachments, image_part);
1429                                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1430                                                                         image_part);
1431                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1432                                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1433                                 gtk_widget_show_all (priv->attachments_caption);
1434                         } else if (image_file_id == -1) {
1435                                 close (image_file_id);
1436                         }
1437                 }
1438         }
1439
1440
1441 }
1442
1443 void
1444 modest_msg_edit_window_attach_file (ModestMsgEditWindow *window)
1445 {
1446         
1447         ModestMsgEditWindowPrivate *priv;
1448         GtkWidget *dialog = NULL;
1449         gint response = 0;
1450         gchar *uri = NULL, *filename = NULL;
1451         
1452         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1453         
1454         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1455
1456         response = gtk_dialog_run (GTK_DIALOG (dialog));
1457         switch (response) {
1458         case GTK_RESPONSE_OK:
1459                 uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1460                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1461                 break;
1462         default:
1463                 break;
1464         }
1465         gtk_widget_destroy (dialog);
1466
1467         if (uri) {
1468
1469                 GnomeVFSHandle *handle = NULL;
1470                 GnomeVFSResult result;
1471
1472                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1473                 if (result == GNOME_VFS_OK) {
1474                         TnyMimePart *mime_part;
1475                         TnyStream *stream;
1476                         const gchar *mime_type = NULL;
1477                         gchar *basename;
1478                         gchar *content_id;
1479                         GnomeVFSFileInfo info;
1480                         
1481                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
1482                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1483                         mime_part = tny_platform_factory_new_mime_part
1484                                 (modest_runtime_get_platform_factory ());
1485                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1486                         
1487                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1488                         
1489                         content_id = g_strdup_printf ("%d", priv->last_cid);
1490                         tny_mime_part_set_content_id (mime_part, content_id);
1491                         g_free (content_id);
1492                         priv->last_cid++;
1493                         
1494                         basename = g_path_get_basename (filename);
1495                         tny_mime_part_set_filename (mime_part, basename);
1496                         g_free (basename);
1497                         
1498                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1499                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1500                                                                 mime_part);
1501                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1502                         gtk_widget_show_all (priv->attachments_caption);
1503                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1504                 } 
1505                 g_free (filename);
1506         }
1507 }
1508
1509 void
1510 modest_msg_edit_window_attach_file_noninteractive (
1511                 ModestMsgEditWindow *window,
1512                 gchar *filename)
1513 {
1514         
1515         ModestMsgEditWindowPrivate *priv;
1516         
1517         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1518
1519         if (filename) {
1520                 gint file_id;
1521                 
1522                 file_id = g_open (filename, O_RDONLY, 0);
1523                 if (file_id != -1) {
1524                         TnyMimePart *mime_part;
1525                         TnyStream *stream;
1526                         const gchar *mime_type;
1527                         gchar *basename;
1528                         gchar *content_id;
1529                         
1530                         mime_type = gnome_vfs_get_file_mime_type_fast (filename, NULL);
1531                         mime_part = tny_platform_factory_new_mime_part
1532                                 (modest_runtime_get_platform_factory ());
1533                         stream = TNY_STREAM (tny_fs_stream_new (file_id));
1534                         
1535                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1536                         
1537                         content_id = g_strdup_printf ("%d", priv->last_cid);
1538                         tny_mime_part_set_content_id (mime_part, content_id);
1539                         g_free (content_id);
1540                         priv->last_cid++;
1541                         
1542                         basename = g_path_get_basename (filename);
1543                         tny_mime_part_set_filename (mime_part, basename);
1544                         g_free (basename);
1545                         
1546                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1547                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1548                                                                 mime_part);
1549                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1550                         gtk_widget_show_all (priv->attachments_caption);
1551                 } else if (file_id == -1) {
1552                         close (file_id);
1553                         g_warning("file to be attached does not exist: %s", filename);
1554                 }
1555         }
1556 }
1557
1558 void
1559 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1560                                           GList *att_list)
1561 {
1562         ModestMsgEditWindowPrivate *priv;
1563         gboolean clean_list = FALSE;
1564
1565         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1566         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1567
1568         if (att_list == NULL) {
1569                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1570                 clean_list = TRUE;
1571         }
1572
1573         if (att_list == NULL) {
1574                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1575         } else {
1576                 GtkWidget *confirmation_dialog = NULL;
1577                 gboolean dialog_response;
1578                 GList *node;
1579                 if (att_list->next == NULL) {
1580                         gchar *message = g_strdup_printf (_("emev_nc_delete_attachment"), 
1581                                                           tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
1582                         confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1583                         g_free (message);
1584                 } else {
1585                         confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), _("emev_nc_delete_attachments"));
1586                 }
1587                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1588                 gtk_widget_destroy (confirmation_dialog);
1589                 if (!dialog_response) {
1590                         if (clean_list)
1591                                 g_list_free (att_list);
1592                         return;
1593                 }
1594                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1595
1596                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1597                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1598                         const gchar *att_id;
1599                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1600
1601                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1602                                                                    mime_part);
1603                         if (priv->attachments == NULL)
1604                                 gtk_widget_hide (priv->attachments_caption);
1605                         att_id = tny_mime_part_get_content_id (mime_part);
1606                         if (att_id != NULL)
1607                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1608                                                                  att_id);
1609                         g_object_unref (mime_part);
1610                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1611                 }
1612         }
1613
1614         if (clean_list)
1615                 g_list_free (att_list);
1616 }
1617
1618 static void
1619 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1620                                             gpointer userdata)
1621 {
1622         ModestMsgEditWindowPrivate *priv;
1623         GdkColor *new_color;
1624         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1625         
1626 #ifdef MODEST_HILDON_VERSION_0  
1627         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1628 #else 
1629         GdkColor col;
1630         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1631         new_color = &col;
1632 #endif /*MODEST_HILDON_VERSION_0*/
1633
1634         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1635         
1636         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1637
1638 }
1639
1640 static void
1641 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1642                                     gpointer userdata)
1643 {
1644         ModestMsgEditWindowPrivate *priv;
1645         gint new_size_index;
1646         ModestMsgEditWindow *window;
1647         GtkWidget *label;
1648         
1649         window = MODEST_MSG_EDIT_WINDOW (userdata);
1650         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1651         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1652
1653         if (gtk_check_menu_item_get_active (menu_item)) {
1654                 gchar *markup;
1655                 WPTextBufferFormat format;
1656
1657                 memset (&format, 0, sizeof (format));
1658                 wp_text_buffer_get_current_state (WP_TEXT_BUFFER (priv->text_buffer), &format);
1659
1660                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1661                 
1662                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1663                 format.cs.font_size = TRUE;
1664                 format.cs.text_position = TRUE;
1665                 format.cs.font = TRUE;
1666                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1667                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format);
1668
1669 /*              if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, */
1670 /*                                                 (gpointer) wp_get_font_size_index (new_size_index, 12))) */
1671 /*                      wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); */
1672                 
1673                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1674                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1675                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1676                 g_free (markup);
1677         }
1678 }
1679
1680 static void
1681 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1682                                     gpointer userdata)
1683 {
1684         ModestMsgEditWindowPrivate *priv;
1685         gint new_font_index;
1686         ModestMsgEditWindow *window;
1687         GtkWidget *label;
1688         
1689         window = MODEST_MSG_EDIT_WINDOW (userdata);
1690         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1691         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1692
1693         if (gtk_check_menu_item_get_active (menu_item)) {
1694                 gchar *markup;
1695
1696                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1697                 
1698                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1699
1700                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1701                                                    (gpointer) new_font_index))
1702                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1703                 
1704                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1705                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1706                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1707                 g_free (markup);
1708         }
1709 }
1710
1711 static void
1712 modest_msg_edit_window_set_zoom (ModestWindow *window,
1713                                  gdouble zoom)
1714 {
1715         ModestMsgEditWindowPrivate *priv;
1716      
1717         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1718
1719         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1720         priv->zoom_level = zoom;
1721         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1722 }
1723
1724 static gdouble
1725 modest_msg_edit_window_get_zoom (ModestWindow *window)
1726 {
1727         ModestMsgEditWindowPrivate *priv;
1728      
1729         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1730
1731         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1732         return priv->zoom_level;
1733 }
1734
1735 static gboolean
1736 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1737 {
1738         ModestWindowPrivate *parent_priv;
1739         GtkRadioAction *zoom_radio_action;
1740         GSList *group, *node;
1741
1742         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1743         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1744                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1745
1746         group = gtk_radio_action_get_group (zoom_radio_action);
1747
1748         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1749                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_max_zoom_level"));
1750                 return FALSE;
1751         }
1752
1753         for (node = group; node != NULL; node = g_slist_next (node)) {
1754                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1755                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1756                         return TRUE;
1757                 }
1758         }
1759         return FALSE;
1760 }
1761
1762 static gboolean
1763 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1764 {
1765         ModestWindowPrivate *parent_priv;
1766         GtkRadioAction *zoom_radio_action;
1767         GSList *group, *node;
1768
1769         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1770         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1771                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1772
1773         group = gtk_radio_action_get_group (zoom_radio_action);
1774
1775         for (node = group; node != NULL; node = g_slist_next (node)) {
1776                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1777                         if (node->next != NULL) {
1778                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1779                                 return TRUE;
1780                         } else
1781                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_min_zoom_level"));
1782                         break;
1783                 }
1784         }
1785         return FALSE;
1786 }
1787
1788 static gboolean
1789 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1790 {
1791         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1792                 ModestWindowPrivate *parent_priv;
1793                 ModestWindowMgr *mgr;
1794                 gboolean is_fullscreen;
1795                 GtkAction *fs_toggle_action;
1796                 gboolean active;
1797
1798                 mgr = modest_runtime_get_window_mgr ();
1799                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1800
1801                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1802                 
1803                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1804                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1805                 if (is_fullscreen != active)
1806                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1807         }
1808
1809         return FALSE;
1810
1811 }
1812
1813 void
1814 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1815 {
1816         ModestWindowPrivate *parent_priv;
1817         GtkAction *fs_toggle_action;
1818         gboolean active;
1819
1820         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1821
1822         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1823         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1824         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1825 }
1826
1827 void
1828 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1829                                 gboolean show)
1830 {
1831         ModestMsgEditWindowPrivate *priv = NULL;
1832         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1833
1834         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1835         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1836         if (show)
1837                 gtk_widget_show (priv->cc_caption);
1838         else
1839                 gtk_widget_hide (priv->cc_caption);
1840         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
1841 }
1842
1843 void
1844 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1845                                  gboolean show)
1846 {
1847         ModestMsgEditWindowPrivate *priv = NULL;
1848         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1849
1850         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1851         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1852         if (show)
1853                 gtk_widget_show (priv->bcc_caption);
1854         else
1855                 gtk_widget_hide (priv->bcc_caption);
1856         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
1857 }
1858
1859 static void
1860 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
1861                                          ModestRecptEditor *editor)
1862 {
1863         ModestMsgEditWindowPrivate *priv;
1864
1865         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1866         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
1867         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1868
1869         if (editor == NULL) {
1870                 GtkWidget *view_focus;
1871                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
1872
1873                 /* This code should be kept in sync with ModestRecptEditor. The
1874                    textview inside the recpt editor is the one that really gets the
1875                    focus. As it's inside a scrolled window, and this one inside the
1876                    hbox recpt editor inherits from, we'll need to go up in the 
1877                    hierarchy to know if the text view is part of the recpt editor
1878                    or if it's a different text entry */
1879
1880                 if (gtk_widget_get_parent (view_focus)) {
1881                         GtkWidget *first_parent;
1882
1883                         first_parent = gtk_widget_get_parent (view_focus);
1884                         if (gtk_widget_get_parent (first_parent) && 
1885                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
1886                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
1887                         }
1888                 }
1889
1890                 if (editor == NULL)
1891                         editor = MODEST_RECPT_EDITOR (priv->to_field);
1892
1893         }
1894
1895         modest_address_book_select_addresses (editor);
1896
1897 }
1898
1899 void
1900 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
1901 {
1902         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1903
1904         modest_msg_edit_window_open_addressbook (window, NULL);
1905 }
1906
1907 static void
1908 modest_msg_edit_window_show_toolbar (ModestWindow *self,
1909                                      gboolean show_toolbar)
1910 {
1911         ModestWindowPrivate *parent_priv;
1912         
1913         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1914         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1915
1916         /* FIXME: we can not just use the code of
1917            modest_msg_edit_window_setup_toolbar because it has a
1918            mixture of both initialization and creation code. */
1919
1920         if (show_toolbar)
1921                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1922         else
1923                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1924 }
1925
1926 void
1927 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
1928                                            TnyHeaderFlags priority_flags)
1929 {
1930         ModestMsgEditWindowPrivate *priv;
1931
1932         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1933
1934         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1935         priority_flags = priority_flags & (TNY_HEADER_FLAG_HIGH_PRIORITY);
1936
1937         if (priv->priority_flags != priority_flags) {
1938
1939                 priv->priority_flags = priority_flags;
1940
1941                 switch (priority_flags) {
1942                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
1943                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
1944                         gtk_widget_show (priv->priority_icon);
1945                         break;
1946                 case TNY_HEADER_FLAG_LOW_PRIORITY:
1947                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
1948                         gtk_widget_show (priv->priority_icon);
1949                         break;
1950                 default:
1951                         gtk_widget_hide (priv->priority_icon);
1952                         break;
1953                 }
1954         }
1955 }
1956
1957 void
1958 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
1959                                         gint file_format)
1960 {
1961         ModestMsgEditWindowPrivate *priv;
1962         gint current_format;
1963
1964         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1965
1966         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1967
1968         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
1969                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
1970
1971         if (current_format != file_format) {
1972                 switch (file_format) {
1973                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
1974                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1975                         break;
1976                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
1977                 {
1978                         GtkWidget *dialog;
1979                         gint response;
1980                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
1981                         response = gtk_dialog_run (GTK_DIALOG (dialog));
1982                         gtk_widget_destroy (dialog);
1983                         if (response == GTK_RESPONSE_OK)
1984                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1985                 }
1986                         break;
1987                 }
1988                 update_dimmed (window);
1989         }
1990 }
1991
1992 void
1993 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
1994 {
1995         GtkWidget *dialog;
1996         ModestMsgEditWindowPrivate *priv;
1997         WPTextBufferFormat oldfmt, fmt;
1998         gint old_position = 0;
1999         gint response = 0;
2000         gint position = 0;
2001         gint font_size;
2002         GdkColor *color = NULL;
2003         gboolean bold, bold_set, italic, italic_set;
2004         gboolean underline, underline_set;
2005         gboolean strikethrough, strikethrough_set;
2006         gboolean position_set;
2007         gboolean font_size_set, font_set, color_set;
2008         gchar *font_name;
2009
2010         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2011         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2012         
2013         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2014
2015         /* First we get the currently selected font information */
2016         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2017         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2018
2019         switch (oldfmt.text_position) {
2020         case TEXT_POSITION_NORMAL:
2021                 old_position = 0;
2022                 break;
2023         case TEXT_POSITION_SUPERSCRIPT:
2024                 old_position = 1;
2025                 break;
2026         default:
2027                 old_position = -1;
2028                 break;
2029         }
2030
2031         g_object_set (G_OBJECT (dialog),
2032                       "bold", oldfmt.bold != FALSE,
2033                       "bold-set", !oldfmt.cs.bold,
2034                       "underline", oldfmt.underline != FALSE,
2035                       "underline-set", !oldfmt.cs.underline,
2036                       "italic", oldfmt.italic != FALSE,
2037                       "italic-set", !oldfmt.cs.italic,
2038                       "strikethrough", oldfmt.strikethrough != FALSE,
2039                       "strikethrough-set", !oldfmt.cs.strikethrough,
2040                       "color", &oldfmt.color,
2041                       "color-set", !oldfmt.cs.color,
2042                       "size", wp_font_size[oldfmt.font_size],
2043                       "size-set", !oldfmt.cs.font_size,
2044                       "position", old_position,
2045                       "position-set", !oldfmt.cs.text_position,
2046                       "family", wp_get_font_name (oldfmt.font),
2047                       "family-set", !oldfmt.cs.font,
2048                       NULL);
2049
2050         gtk_widget_show_all (dialog);
2051         response = gtk_dialog_run (GTK_DIALOG (dialog));
2052         if (response == GTK_RESPONSE_OK) {
2053
2054                 g_object_get( dialog,
2055                               "bold", &bold,
2056                               "bold-set", &bold_set,
2057                               "underline", &underline,
2058                               "underline-set", &underline_set,
2059                               "italic", &italic,
2060                               "italic-set", &italic_set,
2061                               "strikethrough", &strikethrough,
2062                               "strikethrough-set", &strikethrough_set,
2063                               "color", &color,
2064                               "color-set", &color_set,
2065                               "size", &font_size,
2066                               "size-set", &font_size_set,
2067                               "family", &font_name,
2068                               "family-set", &font_set,
2069                               "position", &position,
2070                               "position-set", &position_set,
2071                               NULL );
2072                 
2073         }       
2074
2075         if (response == GTK_RESPONSE_OK) {
2076                 memset(&fmt, 0, sizeof(fmt));
2077                 if (bold_set) {
2078                         fmt.bold = bold;
2079                         fmt.cs.bold = TRUE;
2080                 }
2081                 if (italic_set) {
2082                         fmt.italic = italic;
2083                         fmt.cs.italic = TRUE;
2084                 }
2085                 if (underline_set) {
2086                         fmt.underline = underline;
2087                         fmt.cs.underline = TRUE;
2088                 }
2089                 if (strikethrough_set) {
2090                         fmt.strikethrough = strikethrough;
2091                         fmt.cs.strikethrough = TRUE;
2092                 }
2093                 if (position_set) {
2094                         fmt.text_position =
2095                                 ( position == 0 )
2096                                 ? TEXT_POSITION_NORMAL
2097                                 : ( ( position == 1 )
2098                                     ? TEXT_POSITION_SUPERSCRIPT
2099                                     : TEXT_POSITION_SUBSCRIPT );
2100                         fmt.cs.text_position = TRUE;
2101                 }
2102                 if (color_set) {
2103                         fmt.color = *color;
2104                         fmt.cs.color = TRUE;
2105                 }
2106                 if (font_set) {
2107                         fmt.font = wp_get_font_index(font_name,
2108                                                      DEFAULT_FONT);
2109                         fmt.cs.font = TRUE;
2110                 }
2111                 g_free(font_name);
2112                 if (font_size_set) {
2113                         fmt.font_size = wp_get_font_size_index(
2114                                 font_size, DEFAULT_FONT_SIZE);
2115                         fmt.cs.font_size = TRUE;
2116                 }
2117                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2118         }
2119         gtk_widget_destroy (dialog);
2120         
2121         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2122 }
2123
2124 void
2125 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2126 {
2127         ModestMsgEditWindowPrivate *priv;
2128
2129         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2130         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2131         
2132         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2133
2134         update_dimmed (window);
2135
2136 }
2137
2138 static void
2139 update_dimmed (ModestMsgEditWindow *window)
2140 {
2141         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2142         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2143         GtkAction *action;
2144         GtkWidget *widget;
2145         gboolean rich_text;
2146         gboolean editor_focused;
2147
2148         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2149         editor_focused = gtk_widget_is_focus (priv->msg_body);
2150
2151         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2152         gtk_action_set_sensitive (action, rich_text && editor_focused);
2153         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2154         gtk_action_set_sensitive (action, rich_text && editor_focused);
2155         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2156         gtk_action_set_sensitive (action, rich_text && editor_focused);
2157         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2158         gtk_action_set_sensitive (action, rich_text && editor_focused);
2159         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2160         gtk_action_set_sensitive (action, rich_text && editor_focused);
2161         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2162         gtk_action_set_sensitive (action, rich_text && editor_focused);
2163         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2164         gtk_action_set_sensitive (action, rich_text && editor_focused);
2165         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2166         gtk_action_set_sensitive (action, rich_text && editor_focused);
2167         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2168         gtk_action_set_sensitive (action, rich_text && editor_focused);
2169         widget = priv->font_color_button;
2170         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2171         widget = priv->font_size_toolitem;
2172         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2173         widget = priv->font_face_toolitem;
2174         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2175 }
2176
2177 static void
2178 setup_insensitive_handlers (ModestMsgEditWindow *window)
2179 {
2180         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2181         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2182         GtkWidget *widget;
2183
2184         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2185         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2186         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2187         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2188
2189         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2190         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2191         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2192         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2193         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2194         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2195         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2196         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2197         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2198         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2199         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2200         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2201         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2202         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2203         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2204         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2205         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2206         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2207         widget = priv->font_color_button;
2208         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2209         widget = priv->font_size_toolitem;
2210         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2211         widget = priv->font_face_toolitem;
2212         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2213
2214 }
2215
2216 static void  
2217 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2218 {
2219         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2220         GtkAction *action;
2221
2222         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2223         gtk_action_set_sensitive (action, can_undo);
2224 }
2225
2226 static void
2227 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2228 {
2229         GtkTextIter iter;
2230         GtkTextIter match_start, match_end;
2231
2232         if (image_id == NULL)
2233                 return;
2234
2235         gtk_text_buffer_get_start_iter (buffer, &iter);
2236
2237         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2238                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2239                 GSList *node;
2240                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2241                         GtkTextTag *tag = (GtkTextTag *) node->data;
2242                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2243                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2244                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2245                                         gint offset;
2246                                         offset = gtk_text_iter_get_offset (&match_start);
2247                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2248                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2249                                 }
2250                         }
2251                 }
2252                 gtk_text_iter_forward_char (&iter);
2253         }
2254 }
2255
2256 static void
2257 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2258 {
2259         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2260         GtkTextIter real_start, real_end;
2261         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2262
2263         if (gtk_text_iter_compare (start, end) > 0) {
2264                 real_start = *end;
2265                 real_end = *start;
2266         } else {
2267                 real_start = *start;
2268                 real_end = *end;
2269         }
2270         do {
2271                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2272                 GSList *node;
2273                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2274                         GtkTextTag *tag = (GtkTextTag *) node->data;
2275                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2276                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2277
2278                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2279                                                                                  image_id);
2280                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2281                         }
2282                 }
2283         } while (gtk_text_iter_forward_char (&real_start)&&
2284                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2285 }
2286
2287 static gboolean
2288 msg_body_focus (GtkWidget *focus,
2289                 GdkEventFocus *event,
2290                 gpointer userdata)
2291 {
2292         
2293         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2294         return FALSE;
2295 }
2296
2297 static void
2298 recpt_field_changed (GtkTextBuffer *buffer,
2299                   ModestMsgEditWindow *editor)
2300 {
2301         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2302         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2303         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2304         gboolean dim = FALSE;
2305         GtkAction *action;
2306
2307         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2308         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2309         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2310         
2311         dim = ((gtk_text_buffer_get_char_count (to_buffer) + 
2312                 gtk_text_buffer_get_char_count (cc_buffer) +
2313                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2314                         
2315         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2316         gtk_action_set_sensitive (action, !dim);
2317         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2318         gtk_action_set_sensitive (action, !dim);
2319 }
2320
2321 static void  
2322 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2323 {
2324         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2325 }
2326
2327 static void
2328 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2329 {
2330         gboolean rich_text, editor_focused;
2331
2332         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2333         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2334         editor_focused = gtk_widget_is_focus (priv->msg_body);
2335
2336         if (!rich_text)
2337                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2338         else if (!editor_focused)
2339                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2340 }
2341
2342 static void
2343 reset_modified (ModestMsgEditWindow *editor)
2344 {
2345         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2346         GtkTextBuffer *buffer;
2347
2348         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2349         gtk_text_buffer_set_modified (buffer, FALSE);
2350         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2351         gtk_text_buffer_set_modified (buffer, FALSE);
2352         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2353         gtk_text_buffer_set_modified (buffer, FALSE);
2354         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2355 }
2356
2357 static gboolean
2358 is_modified (ModestMsgEditWindow *editor)
2359 {
2360         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2361         GtkTextBuffer *buffer;
2362
2363         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2364         if (gtk_text_buffer_get_modified (buffer))
2365                 return TRUE;
2366         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2367         if (gtk_text_buffer_get_modified (buffer))
2368                 return TRUE;
2369         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2370         if (gtk_text_buffer_get_modified (buffer))
2371                 return TRUE;
2372         if (gtk_text_buffer_get_modified (priv->text_buffer))
2373                 return TRUE;
2374
2375         return FALSE;
2376 }
2377
2378 gboolean
2379 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2380 {
2381         ModestMsgEditWindowPrivate *priv = NULL;
2382
2383         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2384         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2385
2386         /* check if there's no recipient added */
2387         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2388             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2389             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2390                 /* no recipient contents, then select contacts */
2391                 modest_msg_edit_window_open_addressbook (window, NULL);
2392                 return FALSE;
2393         }
2394
2395         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2396                 return FALSE;
2397         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2398                 return FALSE;
2399         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2400                 return FALSE;
2401
2402         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2403
2404         return TRUE;
2405
2406 }
2407
2408 static void
2409 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2410                                                ModestMsgEditWindow *window)
2411 {
2412         modest_msg_edit_window_attach_file (window);
2413 }
2414
2415 static void
2416 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2417                                                GdkEvent *event,
2418                                                ModestMsgEditWindow *window)
2419 {
2420         ModestWindowPrivate *parent_priv;
2421         GtkAction *action;
2422         gchar *selection;
2423         GtkWidget *focused;
2424
2425         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2426         selection = gtk_clipboard_wait_for_text (clipboard);
2427         focused = gtk_window_get_focus (GTK_WINDOW (window));
2428
2429         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2430         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2431         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2432         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2433 }
2434
2435 static void 
2436 update_window_title (ModestMsgEditWindow *window)
2437 {
2438         ModestMsgEditWindowPrivate *priv = NULL;
2439         const gchar *subject;
2440
2441         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2442         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2443         if (subject == NULL || subject[0] == '\0')
2444                 subject = _("mail_va_new_email");
2445
2446         gtk_window_set_title (GTK_WINDOW (window), subject);
2447
2448 }
2449
2450 static void  
2451 subject_field_changed (GtkEditable *editable, 
2452                        ModestMsgEditWindow *window)
2453 {
2454         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2455         update_window_title (window);
2456         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2457 }