* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #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                 if (!dialog_response) {
1580                         if (clean_list)
1581                                 g_list_free (att_list);
1582                         return;
1583                 }
1584                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1585
1586                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1587                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1588                         const gchar *att_id;
1589                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1590
1591                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1592                                                                    mime_part);
1593                         att_id = tny_mime_part_get_content_id (mime_part);
1594                         if (att_id != NULL)
1595                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1596                                                                  att_id);
1597                         g_object_unref (mime_part);
1598                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1599                 }
1600         }
1601
1602         if (clean_list)
1603                 g_list_free (att_list);
1604 }
1605
1606 static void
1607 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1608                                             gpointer userdata)
1609 {
1610         ModestMsgEditWindowPrivate *priv;
1611         GdkColor *new_color;
1612         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1613         
1614 #ifdef MODEST_HILDON_VERSION_0  
1615         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1616 #else 
1617         GdkColor col;
1618         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1619         new_color = &col;
1620 #endif /*MODEST_HILDON_VERSION_0*/
1621
1622         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1623         
1624         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1625
1626 }
1627
1628 static void
1629 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1630                                     gpointer userdata)
1631 {
1632         ModestMsgEditWindowPrivate *priv;
1633         gint new_size_index;
1634         ModestMsgEditWindow *window;
1635         GtkWidget *label;
1636         
1637         window = MODEST_MSG_EDIT_WINDOW (userdata);
1638         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1639         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1640
1641         if (gtk_check_menu_item_get_active (menu_item)) {
1642                 gchar *markup;
1643                 WPTextBufferFormat format;
1644
1645                 memset (&format, 0, sizeof (format));
1646                 wp_text_buffer_get_current_state (WP_TEXT_BUFFER (priv->text_buffer), &format);
1647
1648                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1649                 
1650                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1651                 format.cs.font_size = TRUE;
1652                 format.cs.text_position = TRUE;
1653                 format.cs.font = TRUE;
1654                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1655                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format);
1656
1657 /*              if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, */
1658 /*                                                 (gpointer) wp_get_font_size_index (new_size_index, 12))) */
1659 /*                      wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); */
1660                 
1661                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1662                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1663                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1664                 g_free (markup);
1665         }
1666 }
1667
1668 static void
1669 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1670                                     gpointer userdata)
1671 {
1672         ModestMsgEditWindowPrivate *priv;
1673         gint new_font_index;
1674         ModestMsgEditWindow *window;
1675         GtkWidget *label;
1676         
1677         window = MODEST_MSG_EDIT_WINDOW (userdata);
1678         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1679         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1680
1681         if (gtk_check_menu_item_get_active (menu_item)) {
1682                 gchar *markup;
1683
1684                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1685                 
1686                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1687
1688                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1689                                                    (gpointer) new_font_index))
1690                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1691                 
1692                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1693                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1694                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1695                 g_free (markup);
1696         }
1697 }
1698
1699 static void
1700 modest_msg_edit_window_set_zoom (ModestWindow *window,
1701                                  gdouble zoom)
1702 {
1703         ModestMsgEditWindowPrivate *priv;
1704      
1705         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1706
1707         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1708         priv->zoom_level = zoom;
1709         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1710 }
1711
1712 static gdouble
1713 modest_msg_edit_window_get_zoom (ModestWindow *window)
1714 {
1715         ModestMsgEditWindowPrivate *priv;
1716      
1717         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1718
1719         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1720         return priv->zoom_level;
1721 }
1722
1723 static gboolean
1724 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1725 {
1726         ModestWindowPrivate *parent_priv;
1727         GtkRadioAction *zoom_radio_action;
1728         GSList *group, *node;
1729
1730         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1731         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1732                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1733
1734         group = gtk_radio_action_get_group (zoom_radio_action);
1735
1736         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1737                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_max_zoom_level"));
1738                 return FALSE;
1739         }
1740
1741         for (node = group; node != NULL; node = g_slist_next (node)) {
1742                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1743                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1744                         return TRUE;
1745                 }
1746         }
1747         return FALSE;
1748 }
1749
1750 static gboolean
1751 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1752 {
1753         ModestWindowPrivate *parent_priv;
1754         GtkRadioAction *zoom_radio_action;
1755         GSList *group, *node;
1756
1757         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1758         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1759                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1760
1761         group = gtk_radio_action_get_group (zoom_radio_action);
1762
1763         for (node = group; node != NULL; node = g_slist_next (node)) {
1764                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1765                         if (node->next != NULL) {
1766                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1767                                 return TRUE;
1768                         } else
1769                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_min_zoom_level"));
1770                         break;
1771                 }
1772         }
1773         return FALSE;
1774 }
1775
1776 static gboolean
1777 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1778 {
1779         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1780                 ModestWindowPrivate *parent_priv;
1781                 ModestWindowMgr *mgr;
1782                 gboolean is_fullscreen;
1783                 GtkAction *fs_toggle_action;
1784                 gboolean active;
1785
1786                 mgr = modest_runtime_get_window_mgr ();
1787                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1788
1789                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1790                 
1791                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1792                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1793                 if (is_fullscreen != active)
1794                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1795         }
1796
1797         return FALSE;
1798
1799 }
1800
1801 void
1802 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1803 {
1804         ModestWindowPrivate *parent_priv;
1805         GtkAction *fs_toggle_action;
1806         gboolean active;
1807
1808         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1809
1810         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1811         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1812         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1813 }
1814
1815 void
1816 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1817                                 gboolean show)
1818 {
1819         ModestMsgEditWindowPrivate *priv = NULL;
1820         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1821
1822         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1823         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1824         if (show)
1825                 gtk_widget_show (priv->cc_caption);
1826         else
1827                 gtk_widget_hide (priv->cc_caption);
1828         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
1829 }
1830
1831 void
1832 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1833                                  gboolean show)
1834 {
1835         ModestMsgEditWindowPrivate *priv = NULL;
1836         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1837
1838         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1839         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1840         if (show)
1841                 gtk_widget_show (priv->bcc_caption);
1842         else
1843                 gtk_widget_hide (priv->bcc_caption);
1844         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
1845 }
1846
1847 static void
1848 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
1849                                          ModestRecptEditor *editor)
1850 {
1851         ModestMsgEditWindowPrivate *priv;
1852
1853         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1854         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
1855         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1856
1857         if (editor == NULL) {
1858                 GtkWidget *view_focus;
1859                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
1860
1861                 /* This code should be kept in sync with ModestRecptEditor. The
1862                    textview inside the recpt editor is the one that really gets the
1863                    focus. As it's inside a scrolled window, and this one inside the
1864                    hbox recpt editor inherits from, we'll need to go up in the 
1865                    hierarchy to know if the text view is part of the recpt editor
1866                    or if it's a different text entry */
1867
1868                 if (gtk_widget_get_parent (view_focus)) {
1869                         GtkWidget *first_parent;
1870
1871                         first_parent = gtk_widget_get_parent (view_focus);
1872                         if (gtk_widget_get_parent (first_parent) && 
1873                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
1874                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
1875                         }
1876                 }
1877
1878                 if (editor == NULL)
1879                         editor = MODEST_RECPT_EDITOR (priv->to_field);
1880
1881         }
1882
1883         modest_address_book_select_addresses (editor);
1884
1885 }
1886
1887 void
1888 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
1889 {
1890         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1891
1892         modest_msg_edit_window_open_addressbook (window, NULL);
1893 }
1894
1895 static void
1896 modest_msg_edit_window_show_toolbar (ModestWindow *self,
1897                                      gboolean show_toolbar)
1898 {
1899         ModestWindowPrivate *parent_priv;
1900         
1901         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1902         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1903
1904         /* FIXME: we can not just use the code of
1905            modest_msg_edit_window_setup_toolbar because it has a
1906            mixture of both initialization and creation code. */
1907
1908         if (show_toolbar)
1909                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1910         else
1911                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1912 }
1913
1914 void
1915 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
1916                                            TnyHeaderFlags priority_flags)
1917 {
1918         ModestMsgEditWindowPrivate *priv;
1919
1920         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1921
1922         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1923         priority_flags = priority_flags & (TNY_HEADER_FLAG_HIGH_PRIORITY);
1924
1925         if (priv->priority_flags != priority_flags) {
1926
1927                 priv->priority_flags = priority_flags;
1928
1929                 switch (priority_flags) {
1930                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
1931                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
1932                         gtk_widget_show (priv->priority_icon);
1933                         break;
1934                 case TNY_HEADER_FLAG_LOW_PRIORITY:
1935                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
1936                         gtk_widget_show (priv->priority_icon);
1937                         break;
1938                 default:
1939                         gtk_widget_hide (priv->priority_icon);
1940                         break;
1941                 }
1942         }
1943 }
1944
1945 void
1946 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
1947                                         gint file_format)
1948 {
1949         ModestMsgEditWindowPrivate *priv;
1950         gint current_format;
1951
1952         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1953
1954         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1955
1956         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
1957                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
1958
1959         if (current_format != file_format) {
1960                 switch (file_format) {
1961                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
1962                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1963                         break;
1964                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
1965                 {
1966                         GtkWidget *dialog;
1967                         gint response;
1968                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
1969                         response = gtk_dialog_run (GTK_DIALOG (dialog));
1970                         gtk_widget_destroy (dialog);
1971                         if (response == GTK_RESPONSE_OK)
1972                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1973                 }
1974                         break;
1975                 }
1976                 update_dimmed (window);
1977         }
1978 }
1979
1980 void
1981 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
1982 {
1983         GtkWidget *dialog;
1984         ModestMsgEditWindowPrivate *priv;
1985         WPTextBufferFormat oldfmt, fmt;
1986         gint old_position = 0;
1987         gint response = 0;
1988         gint position = 0;
1989         gint font_size;
1990         GdkColor *color = NULL;
1991         gboolean bold, bold_set, italic, italic_set;
1992         gboolean underline, underline_set;
1993         gboolean strikethrough, strikethrough_set;
1994         gboolean position_set;
1995         gboolean font_size_set, font_set, color_set;
1996         gchar *font_name;
1997
1998         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1999         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2000         
2001         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2002
2003         /* First we get the currently selected font information */
2004         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2005         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2006
2007         switch (oldfmt.text_position) {
2008         case TEXT_POSITION_NORMAL:
2009                 old_position = 0;
2010                 break;
2011         case TEXT_POSITION_SUPERSCRIPT:
2012                 old_position = 1;
2013                 break;
2014         default:
2015                 old_position = -1;
2016                 break;
2017         }
2018
2019         g_object_set (G_OBJECT (dialog),
2020                       "bold", oldfmt.bold != FALSE,
2021                       "bold-set", !oldfmt.cs.bold,
2022                       "underline", oldfmt.underline != FALSE,
2023                       "underline-set", !oldfmt.cs.underline,
2024                       "italic", oldfmt.italic != FALSE,
2025                       "italic-set", !oldfmt.cs.italic,
2026                       "strikethrough", oldfmt.strikethrough != FALSE,
2027                       "strikethrough-set", !oldfmt.cs.strikethrough,
2028                       "color", &oldfmt.color,
2029                       "color-set", !oldfmt.cs.color,
2030                       "size", wp_font_size[oldfmt.font_size],
2031                       "size-set", !oldfmt.cs.font_size,
2032                       "position", old_position,
2033                       "position-set", !oldfmt.cs.text_position,
2034                       "family", wp_get_font_name (oldfmt.font),
2035                       "family-set", !oldfmt.cs.font,
2036                       NULL);
2037
2038         gtk_widget_show_all (dialog);
2039         response = gtk_dialog_run (GTK_DIALOG (dialog));
2040         if (response == GTK_RESPONSE_OK) {
2041
2042                 g_object_get( dialog,
2043                               "bold", &bold,
2044                               "bold-set", &bold_set,
2045                               "underline", &underline,
2046                               "underline-set", &underline_set,
2047                               "italic", &italic,
2048                               "italic-set", &italic_set,
2049                               "strikethrough", &strikethrough,
2050                               "strikethrough-set", &strikethrough_set,
2051                               "color", &color,
2052                               "color-set", &color_set,
2053                               "size", &font_size,
2054                               "size-set", &font_size_set,
2055                               "family", &font_name,
2056                               "family-set", &font_set,
2057                               "position", &position,
2058                               "position-set", &position_set,
2059                               NULL );
2060                 
2061         }       
2062
2063         if (response == GTK_RESPONSE_OK) {
2064                 memset(&fmt, 0, sizeof(fmt));
2065                 if (bold_set) {
2066                         fmt.bold = bold;
2067                         fmt.cs.bold = TRUE;
2068                 }
2069                 if (italic_set) {
2070                         fmt.italic = italic;
2071                         fmt.cs.italic = TRUE;
2072                 }
2073                 if (underline_set) {
2074                         fmt.underline = underline;
2075                         fmt.cs.underline = TRUE;
2076                 }
2077                 if (strikethrough_set) {
2078                         fmt.strikethrough = strikethrough;
2079                         fmt.cs.strikethrough = TRUE;
2080                 }
2081                 if (position_set) {
2082                         fmt.text_position =
2083                                 ( position == 0 )
2084                                 ? TEXT_POSITION_NORMAL
2085                                 : ( ( position == 1 )
2086                                     ? TEXT_POSITION_SUPERSCRIPT
2087                                     : TEXT_POSITION_SUBSCRIPT );
2088                         fmt.cs.text_position = TRUE;
2089                 }
2090                 if (color_set) {
2091                         fmt.color = *color;
2092                         fmt.cs.color = TRUE;
2093                 }
2094                 if (font_set) {
2095                         fmt.font = wp_get_font_index(font_name,
2096                                                      DEFAULT_FONT);
2097                         fmt.cs.font = TRUE;
2098                 }
2099                 g_free(font_name);
2100                 if (font_size_set) {
2101                         fmt.font_size = wp_get_font_size_index(
2102                                 font_size, DEFAULT_FONT_SIZE);
2103                         fmt.cs.font_size = TRUE;
2104                 }
2105                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2106         }
2107         gtk_widget_destroy (dialog);
2108         
2109         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2110 }
2111
2112 void
2113 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2114 {
2115         ModestMsgEditWindowPrivate *priv;
2116
2117         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2118         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2119         
2120         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2121
2122         update_dimmed (window);
2123
2124 }
2125
2126 static void
2127 update_dimmed (ModestMsgEditWindow *window)
2128 {
2129         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2130         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2131         GtkAction *action;
2132         GtkWidget *widget;
2133         gboolean rich_text;
2134         gboolean editor_focused;
2135
2136         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2137         editor_focused = gtk_widget_is_focus (priv->msg_body);
2138
2139         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2140         gtk_action_set_sensitive (action, rich_text && editor_focused);
2141         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2142         gtk_action_set_sensitive (action, rich_text && editor_focused);
2143         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2144         gtk_action_set_sensitive (action, rich_text && editor_focused);
2145         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2146         gtk_action_set_sensitive (action, rich_text && editor_focused);
2147         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2148         gtk_action_set_sensitive (action, rich_text && editor_focused);
2149         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2150         gtk_action_set_sensitive (action, rich_text && editor_focused);
2151         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2152         gtk_action_set_sensitive (action, rich_text && editor_focused);
2153         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2154         gtk_action_set_sensitive (action, rich_text && editor_focused);
2155         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2156         gtk_action_set_sensitive (action, rich_text && editor_focused);
2157         widget = priv->font_color_button;
2158         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2159         widget = priv->font_size_toolitem;
2160         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2161         widget = priv->font_face_toolitem;
2162         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2163 }
2164
2165 static void
2166 setup_insensitive_handlers (ModestMsgEditWindow *window)
2167 {
2168         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2169         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2170         GtkWidget *widget;
2171
2172         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2173         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2174         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2175         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2176
2177         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2178         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2179         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2180         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2181         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2182         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2183         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2184         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2185         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2186         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2187         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2188         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2189         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2190         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2191         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2192         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2193         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2194         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2195         widget = priv->font_color_button;
2196         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2197         widget = priv->font_size_toolitem;
2198         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2199         widget = priv->font_face_toolitem;
2200         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2201
2202 }
2203
2204 static void  
2205 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2206 {
2207         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2208         GtkAction *action;
2209
2210         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2211         gtk_action_set_sensitive (action, can_undo);
2212 }
2213
2214 static void
2215 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2216 {
2217         GtkTextIter iter;
2218         GtkTextIter match_start, match_end;
2219
2220         if (image_id == NULL)
2221                 return;
2222
2223         gtk_text_buffer_get_start_iter (buffer, &iter);
2224
2225         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2226                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2227                 GSList *node;
2228                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2229                         GtkTextTag *tag = (GtkTextTag *) node->data;
2230                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2231                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2232                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2233                                         gint offset;
2234                                         offset = gtk_text_iter_get_offset (&match_start);
2235                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2236                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2237                                 }
2238                         }
2239                 }
2240                 gtk_text_iter_forward_char (&iter);
2241         }
2242 }
2243
2244 static void
2245 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2246 {
2247         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2248         GtkTextIter real_start, real_end;
2249         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2250
2251         if (gtk_text_iter_compare (start, end) > 0) {
2252                 real_start = *end;
2253                 real_end = *start;
2254         } else {
2255                 real_start = *start;
2256                 real_end = *end;
2257         }
2258         do {
2259                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2260                 GSList *node;
2261                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2262                         GtkTextTag *tag = (GtkTextTag *) node->data;
2263                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2264                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2265
2266                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2267                                                                                  image_id);
2268                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2269                         }
2270                 }
2271         } while (gtk_text_iter_forward_char (&real_start)&&
2272                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2273 }
2274
2275 static gboolean
2276 msg_body_focus (GtkWidget *focus,
2277                 GdkEventFocus *event,
2278                 gpointer userdata)
2279 {
2280         
2281         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2282         return FALSE;
2283 }
2284
2285 static void
2286 to_field_changed (GtkTextBuffer *buffer,
2287                   ModestMsgEditWindow *editor)
2288 {
2289         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2290         GtkAction *action;
2291
2292         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2293         gtk_action_set_sensitive (action, gtk_text_buffer_get_char_count (buffer) != 0);
2294         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2295         gtk_action_set_sensitive (action, gtk_text_buffer_get_char_count (buffer) != 0);
2296 }
2297
2298 static void  
2299 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2300 {
2301         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2302 }
2303
2304 static void
2305 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2306 {
2307         gboolean rich_text, editor_focused;
2308
2309         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2310         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2311         editor_focused = gtk_widget_is_focus (priv->msg_body);
2312
2313         if (!rich_text)
2314                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2315         else if (!editor_focused)
2316                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2317 }
2318
2319 static void
2320 reset_modified (ModestMsgEditWindow *editor)
2321 {
2322         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2323         GtkTextBuffer *buffer;
2324
2325         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2326         gtk_text_buffer_set_modified (buffer, FALSE);
2327         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2328         gtk_text_buffer_set_modified (buffer, FALSE);
2329         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2330         gtk_text_buffer_set_modified (buffer, FALSE);
2331         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2332 }
2333
2334 static gboolean
2335 is_modified (ModestMsgEditWindow *editor)
2336 {
2337         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2338         GtkTextBuffer *buffer;
2339
2340         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2341         if (gtk_text_buffer_get_modified (buffer))
2342                 return TRUE;
2343         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2344         if (gtk_text_buffer_get_modified (buffer))
2345                 return TRUE;
2346         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2347         if (gtk_text_buffer_get_modified (buffer))
2348                 return TRUE;
2349         if (gtk_text_buffer_get_modified (priv->text_buffer))
2350                 return TRUE;
2351
2352         return FALSE;
2353 }
2354
2355 gboolean
2356 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2357 {
2358         ModestMsgEditWindowPrivate *priv = NULL;
2359
2360         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2361         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2362
2363         /* check if there's no recipient added */
2364         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2365             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2366             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2367                 /* no recipient contents, then select contacts */
2368                 modest_msg_edit_window_open_addressbook (window, NULL);
2369                 return FALSE;
2370         }
2371
2372         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2373                 return FALSE;
2374         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2375                 return FALSE;
2376         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2377                 return FALSE;
2378
2379         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2380
2381         return TRUE;
2382
2383 }
2384
2385 static void
2386 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2387                                                ModestMsgEditWindow *window)
2388 {
2389         modest_msg_edit_window_attach_file (window);
2390 }
2391
2392 static void
2393 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2394                                                GdkEvent *event,
2395                                                ModestMsgEditWindow *window)
2396 {
2397         ModestWindowPrivate *parent_priv;
2398         GtkAction *action;
2399         gchar *selection;
2400         GtkWidget *focused;
2401
2402         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2403         selection = gtk_clipboard_wait_for_text (clipboard);
2404         focused = gtk_window_get_focus (GTK_WINDOW (window));
2405
2406         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2407         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2408         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2409         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2410 }
2411
2412 static void 
2413 update_window_title (ModestMsgEditWindow *window)
2414 {
2415         ModestMsgEditWindowPrivate *priv = NULL;
2416         const gchar *subject;
2417
2418         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2419         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2420         if (subject == NULL || subject[0] == '\0')
2421                 subject = _("mail_va_new_email");
2422
2423         gtk_window_set_title (GTK_WINDOW (window), subject);
2424
2425 }
2426
2427 static void  
2428 subject_field_changed (GtkEditable *editable, 
2429                        ModestMsgEditWindow *window)
2430 {
2431         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2432         update_window_title (window);
2433         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2434 }