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