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