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