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