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