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