* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37
38 #include <config.h>
39
40 #include <modest-account-mgr.h>
41 #include <modest-account-mgr-helpers.h>
42
43 #include <widgets/modest-msg-edit-window.h>
44 #include <widgets/modest-combo-box.h>
45 #include <widgets/modest-recpt-editor.h>
46 #include <widgets/modest-attachments-view.h>
47
48 #include <modest-runtime.h>
49
50 #include "modest-platform.h"
51 #include "modest-icon-names.h"
52 #include "modest-widget-memory.h"
53 #include "modest-window-priv.h"
54 #include "modest-mail-operation.h"
55 #include "modest-tny-platform-factory.h"
56 #include "modest-tny-msg.h"
57 #include "modest-address-book.h"
58 #include "modest-text-utils.h"
59 #include <tny-simple-list.h>
60 #include <wptextview.h>
61 #include <wptextbuffer.h>
62 #include "modest-scroll-area.h"
63
64 #include "modest-hildon-includes.h"
65 #include "widgets/modest-msg-edit-window-ui.h"
66 #include <libgnomevfs/gnome-vfs-mime.h>
67
68
69 #define DEFAULT_FONT_SIZE 3
70 #define DEFAULT_FONT 2
71 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
72 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
73 #define DEFAULT_MAIN_VBOX_SPACING 6
74 #define SUBJECT_MAX_LENGTH 1000
75
76 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
77 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
78 static void  modest_msg_edit_window_finalize     (GObject *obj);
79
80 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
81 static void  to_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
82 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
83 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
84 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
85 static void  reset_modified (ModestMsgEditWindow *editor);
86 static gboolean is_modified (ModestMsgEditWindow *editor);
87
88 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
89 static void  text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata);
90 static void  text_buffer_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_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
682         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
683         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
684         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
685         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
686         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
687
688         /* Font size and face placeholder */
689         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
690         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
691         /* font_size */
692         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
693         priv->size_tool_button_label = gtk_label_new (NULL);
694         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
695         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
696                               size_text,"</span>", NULL);
697         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
698         g_free (markup);
699         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
700         sizes_menu = gtk_menu_new ();
701         priv->size_items_group = NULL;
702         radio_group = NULL;
703         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
704                 GtkWidget *size_menu_item;
705
706                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
707                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
708                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
709                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
710                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
711                 gtk_widget_show (size_menu_item);
712
713                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
714                         
715         }
716
717         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
718                 GtkWidget *item = (GtkWidget *) node->data;
719                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
720                                   window);
721         }
722
723         priv->size_items_group = g_slist_reverse (priv->size_items_group);
724         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
725         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
726         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
727         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
728         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
729         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
730         priv->font_size_toolitem = tool_item;
731
732         /* font face */
733         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
734         priv->font_tool_button_label = gtk_label_new (NULL);
735         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
736         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
737         g_free(markup);
738         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
739         fonts_menu = gtk_menu_new ();
740         priv->font_items_group = NULL;
741         radio_group = NULL;
742         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
743                 GtkWidget *font_menu_item;
744                 GtkWidget *child_label;
745
746                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
747                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
748                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
749                                       wp_get_font_name (font_index), "</span>", NULL);
750                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
751                 g_free (markup);
752                 
753                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
754                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
755                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
756                 gtk_widget_show (font_menu_item);
757
758                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
759                         
760         }
761         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
762                 GtkWidget *item = (GtkWidget *) node->data;
763                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
764                                   window);
765         }
766         priv->font_items_group = g_slist_reverse (priv->font_items_group);
767         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
768         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
769         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
770         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
771         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
772         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
773         priv->font_face_toolitem = tool_item;
774
775         /* Set expand and homogeneous for remaining items */
776         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
777         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
778         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
779         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
780         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
781         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
782         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
783         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
784         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
785
786
787 }
788
789
790
791 ModestWindow*
792 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
793 {
794         GObject *obj;
795         ModestWindowPrivate *parent_priv;
796         ModestMsgEditWindowPrivate *priv;
797         GtkActionGroup *action_group;
798         GError *error = NULL;
799         GdkPixbuf *window_icon = NULL;
800
801         g_return_val_if_fail (msg, NULL);
802         
803         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
804
805         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
806         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
807
808         parent_priv->ui_manager = gtk_ui_manager_new();
809         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
810         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
811
812         /* Add common actions */
813         gtk_action_group_add_actions (action_group,
814                                       modest_msg_edit_action_entries,
815                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
816                                       obj);
817         gtk_action_group_add_toggle_actions (action_group,
818                                              modest_msg_edit_toggle_action_entries,
819                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
820                                              obj);
821         gtk_action_group_add_radio_actions (action_group,
822                                             modest_msg_edit_alignment_radio_action_entries,
823                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
824                                             GTK_JUSTIFY_LEFT,
825                                             G_CALLBACK (modest_ui_actions_on_change_justify),
826                                             obj);
827         gtk_action_group_add_radio_actions (action_group,
828                                             modest_msg_edit_zoom_action_entries,
829                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
830                                             100,
831                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
832                                             obj);
833         gtk_action_group_add_radio_actions (action_group,
834                                             modest_msg_edit_priority_action_entries,
835                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
836                                             0,
837                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
838                                             obj);
839         gtk_action_group_add_radio_actions (action_group,
840                                             modest_msg_edit_file_format_action_entries,
841                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
842                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
843                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
844                                             obj);
845         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
846         g_object_unref (action_group);
847
848         /* Load the UI definition */
849         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml", &error);
850         if (error != NULL) {
851                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
852                 g_error_free (error);
853                 error = NULL;
854         }
855
856         /* Add accelerators */
857         gtk_window_add_accel_group (GTK_WINDOW (obj), 
858                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
859
860         /* Menubar */
861         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
862         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
863
864         /* Init window */
865         init_window (MODEST_MSG_EDIT_WINDOW(obj));
866
867         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
868                 
869         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
870         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
871
872         g_signal_connect (G_OBJECT(obj), "delete-event",
873                           G_CALLBACK(on_delete_event), obj);
874
875         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
876
877         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
878
879         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
880
881         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
882
883         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
884
885         /* Set window icon */
886         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
887         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
888         
889         return (ModestWindow*)obj;
890 }
891
892 static gint
893 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
894 {
895         GString **string_buffer = (GString **) user_data;
896
897         *string_buffer = g_string_append (*string_buffer, buffer);
898    
899         return 0;
900 }
901
902 static gchar *
903 get_formatted_data (ModestMsgEditWindow *edit_window)
904 {
905         ModestMsgEditWindowPrivate *priv;
906         GString *string_buffer = g_string_new ("");
907         
908         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
909
910         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
911
912         return g_string_free (string_buffer, FALSE);
913                                                                         
914 }
915
916 MsgData * 
917 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
918 {
919         MsgData *data;
920         const gchar *account_name;
921         GtkTextBuffer *buf;
922         GtkTextIter b, e;
923         ModestMsgEditWindowPrivate *priv;
924         
925         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
926
927         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
928                                                                         
929         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
930         g_return_val_if_fail (account_name, NULL);
931         
932         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));        
933         gtk_text_buffer_get_bounds (buf, &b, &e);
934         
935         /* don't free these (except from) */
936         data = g_slice_new0 (MsgData);
937         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
938                                                              account_name);
939         data->to      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->to_field));
940         data->cc      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->cc_field));
941         data->bcc     =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->bcc_field));
942         data->subject =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field));  
943         data->plain_body =  (gchar *) gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE);
944         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
945                 data->html_body = get_formatted_data (edit_window);
946         else
947                 data->html_body = NULL;
948         data->attachments = priv->attachments;
949         data->priority_flags = priv->priority_flags;
950
951         return data;
952 }
953
954 void 
955 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
956                                                       MsgData *data)
957 {
958         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
959
960         g_free (data->from);
961         g_free (data->html_body);
962         g_free (data->plain_body);
963         g_slice_free (MsgData, data);
964 }
965
966 ModestMsgEditFormat
967 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
968 {
969         gboolean rich_text;
970         ModestMsgEditWindowPrivate *priv = NULL;
971         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
972
973         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
974
975         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
976         if (rich_text)
977                 return MODEST_MSG_EDIT_FORMAT_HTML;
978         else
979                 return MODEST_MSG_EDIT_FORMAT_TEXT;
980 }
981
982 void
983 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
984                                    ModestMsgEditFormat format)
985 {
986         ModestMsgEditWindowPrivate *priv;
987
988         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
989         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
990
991         switch (format) {
992         case MODEST_MSG_EDIT_FORMAT_HTML:
993                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
994                 break;
995         case MODEST_MSG_EDIT_FORMAT_TEXT:
996                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
997                 break;
998         default:
999                 g_return_if_reached ();
1000         }
1001 }
1002
1003 ModestMsgEditFormatState *
1004 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1005 {
1006         ModestMsgEditFormatState *format_state = NULL;
1007         ModestMsgEditWindowPrivate *priv;
1008         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1009
1010         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1011         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1012
1013         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1014
1015         format_state = g_new0 (ModestMsgEditFormatState, 1);
1016         format_state->bold = buffer_format->bold&0x1;
1017         format_state->italics = buffer_format->italic&0x1;
1018         format_state->bullet = buffer_format->bullet&0x1;
1019         format_state->color = buffer_format->color;
1020         format_state->font_size = buffer_format->font_size;
1021         format_state->font_family = wp_get_font_name (buffer_format->font);
1022         format_state->justification = buffer_format->justification;
1023         g_free (buffer_format);
1024
1025         return format_state;
1026  
1027 }
1028
1029 void
1030 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1031                                          const ModestMsgEditFormatState *format_state)
1032 {
1033         ModestMsgEditWindowPrivate *priv;
1034         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1035         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1036         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1037         g_return_if_fail (format_state != NULL);
1038
1039         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1040         gtk_widget_grab_focus (priv->msg_body);
1041         buffer_format->bold = (format_state->bold != FALSE);
1042         buffer_format->italic = (format_state->italics != FALSE);
1043         buffer_format->color = format_state->color;
1044         buffer_format->font_size = format_state->font_size;
1045         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1046         buffer_format->justification = format_state->justification;
1047         buffer_format->bullet = format_state->bullet;
1048
1049         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1050
1051         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1052         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1053         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
1054         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1055         buffer_format->cs.font = (buffer_format->font != current_format->font);
1056         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1057         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1058
1059         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1060         if (buffer_format->cs.bold) {
1061                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1062         }
1063         if (buffer_format->cs.italic) {
1064                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1065         }
1066         if (buffer_format->cs.color) {
1067                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1068         }
1069         if (buffer_format->cs.font_size) {
1070                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
1071         }
1072         if (buffer_format->cs.justification) {
1073                 switch (buffer_format->justification) {
1074                 case GTK_JUSTIFY_LEFT:
1075                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1076                         break;
1077                 case GTK_JUSTIFY_CENTER:
1078                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1079                         break;
1080                 case GTK_JUSTIFY_RIGHT:
1081                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1082                         break;
1083                 default:
1084                         break;
1085                 }
1086                         
1087         }
1088         if (buffer_format->cs.font) {
1089                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
1090         }
1091         if (buffer_format->cs.bullet) {
1092                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet));
1093         }
1094 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1095         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1096
1097         g_free (current_format);
1098
1099 }
1100
1101 static void
1102 toggle_action_set_active_block_notify (GtkToggleAction *action,
1103                                        gboolean value)
1104 {
1105         GSList *proxies = NULL;
1106
1107         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1108              proxies != NULL; proxies = g_slist_next (proxies)) {
1109                 GtkWidget *widget = (GtkWidget *) proxies->data;
1110                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
1111         }
1112
1113         gtk_toggle_action_set_active (action, value);
1114
1115         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1116              proxies != NULL; proxies = g_slist_next (proxies)) {
1117                 GtkWidget *widget = (GtkWidget *) proxies->data;
1118                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
1119         }
1120 }
1121
1122 static void
1123 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1124 {
1125         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1126         GtkAction *action;
1127         ModestWindowPrivate *parent_priv;
1128         ModestMsgEditWindowPrivate *priv;
1129         GtkWidget *new_size_menuitem;
1130         GtkWidget *new_font_menuitem;
1131         
1132         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1133         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1134
1135         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1136                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1137                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1138                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1139         } else {
1140                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1141                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1142                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1143         }
1144
1145         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1146         
1147         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1148         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1149
1150         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1151         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1152
1153         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1154         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1155
1156         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1157                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1158                                          window);
1159         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1160         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1161                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1162                                            window);
1163
1164         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1165                                                       buffer_format->font_size))->data);
1166         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1167                 GtkWidget *label;
1168                 gchar *markup;
1169
1170                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1171                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1172                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1173                 g_free (markup);
1174                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1175                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1176                                                  window);
1177                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1178                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1179                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1180                                                    window);
1181         }
1182
1183         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1184                                                       buffer_format->font))->data);
1185         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1186                 GtkWidget *label;
1187                 gchar *markup;
1188
1189                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1190                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1191                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1192                 g_free (markup);
1193                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1194                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1195                                                  window);
1196                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1197                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1198                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1199                                                    window);
1200         }
1201
1202         g_free (buffer_format);
1203
1204 }
1205
1206
1207 void
1208 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1209 {
1210         
1211         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1212         ModestMsgEditWindowPrivate *priv;
1213         GtkWidget *dialog = NULL;
1214         gint response;
1215         const GdkColor *new_color = NULL;
1216         
1217         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1218         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1219         
1220 #ifdef MODEST_HILDON_VERSION_0  
1221         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1222         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1223 #else
1224         dialog = hildon_color_chooser_new ();
1225         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1226 #endif /*MODEST_HILDON_VERSION_0*/              
1227         g_free (buffer_format);
1228
1229         response = gtk_dialog_run (GTK_DIALOG (dialog));
1230         switch (response) {
1231         case GTK_RESPONSE_OK: {
1232 #ifdef MODEST_HILDON_VERSION_0
1233                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1234 #else
1235                 GdkColor col;
1236                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1237                 new_color = &col;
1238 #endif /*MODEST_HILDON_VERSION_0*/
1239         }
1240
1241         break;
1242         default:
1243                 break;
1244         }
1245         gtk_widget_destroy (dialog);
1246
1247         if (new_color != NULL)
1248                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1249
1250 }
1251
1252 void
1253 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1254 {
1255         
1256         ModestMsgEditWindowPrivate *priv;
1257         GtkWidget *dialog = NULL;
1258         gint response;
1259         GdkColor *old_color = NULL;
1260         const GdkColor *new_color = NULL;
1261         
1262         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1263         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1264         
1265 #ifdef MODEST_HILDON_VERSION_0  
1266         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1267         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1268 #else
1269         dialog = hildon_color_chooser_new ();
1270         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1271 #endif /*MODEST_HILDON_VERSION_9*/              
1272
1273         response = gtk_dialog_run (GTK_DIALOG (dialog));
1274         switch (response) {
1275         case GTK_RESPONSE_OK: {
1276 #ifdef MODEST_HILDON_VERSION_0
1277                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1278 #else
1279                 GdkColor col;
1280                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1281                 new_color = &col;
1282 #endif /*MODEST_HILDON_VERSION_0*/
1283           }
1284                 break;
1285         default:
1286                 break;
1287         }
1288         gtk_widget_destroy (dialog);
1289
1290         if (new_color != NULL)
1291                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1292
1293 }
1294
1295 void
1296 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1297 {
1298         
1299         ModestMsgEditWindowPrivate *priv;
1300         GtkWidget *dialog = NULL;
1301         gint response = 0;
1302         gchar *filename = NULL;
1303         
1304         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1305         
1306         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1307
1308         response = gtk_dialog_run (GTK_DIALOG (dialog));
1309         switch (response) {
1310         case GTK_RESPONSE_OK:
1311                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1312                 break;
1313         default:
1314                 break;
1315         }
1316         gtk_widget_destroy (dialog);
1317
1318         if (filename) {
1319                 GdkPixbuf *pixbuf = NULL;
1320                 GtkTextIter position;
1321                 GtkTextMark *insert_mark;
1322
1323                 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1324                 if (pixbuf) {
1325                         gint image_file_id;
1326                         GdkPixbufFormat *pixbuf_format;
1327
1328                         image_file_id = g_open (filename, O_RDONLY, 0);
1329                         pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
1330                         if ((image_file_id != -1)&&(pixbuf_format != NULL)) {
1331                                 TnyMimePart *image_part;
1332                                 TnyStream *image_stream;
1333                                 gchar **mime_types;
1334                                 gchar *mime_type;
1335                                 gchar *basename;
1336                                 gchar *content_id;
1337
1338                                 mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format);
1339                                 if ((mime_types != NULL) && (mime_types[0] != NULL)) {
1340                                         mime_type = mime_types[0];
1341                                 } else {
1342                                         mime_type = "image/unknown";
1343                                 }
1344                                 image_part = tny_platform_factory_new_mime_part
1345                                         (modest_runtime_get_platform_factory ());
1346                                 image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id));
1347
1348                                 tny_mime_part_construct_from_stream (image_part, image_stream, mime_type);
1349                                 g_strfreev (mime_types);
1350
1351                                 content_id = g_strdup_printf ("%d", priv->last_cid);
1352                                 tny_mime_part_set_content_id (image_part, content_id);
1353                                 g_free (content_id);
1354                                 priv->last_cid++;
1355
1356                                 basename = g_path_get_basename (filename);
1357                                 tny_mime_part_set_filename (image_part, basename);
1358                                 g_free (basename);
1359                                 
1360                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1361                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1362                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf);
1363                                 priv->attachments = g_list_prepend (priv->attachments, image_part);
1364                                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1365                                                                         image_part);
1366                                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1367                                 gtk_widget_show_all (priv->attachments_caption);
1368                         } else if (image_file_id == -1) {
1369                                 close (image_file_id);
1370                         }
1371                 }
1372         }
1373
1374
1375 }
1376
1377 void
1378 modest_msg_edit_window_attach_file (ModestMsgEditWindow *window)
1379 {
1380         
1381         ModestMsgEditWindowPrivate *priv;
1382         GtkWidget *dialog = NULL;
1383         gint response = 0;
1384         gchar *filename = NULL;
1385         
1386         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1387         
1388         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1389
1390         response = gtk_dialog_run (GTK_DIALOG (dialog));
1391         switch (response) {
1392         case GTK_RESPONSE_OK:
1393                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1394                 break;
1395         default:
1396                 break;
1397         }
1398         gtk_widget_destroy (dialog);
1399
1400         if (filename) {
1401                 gint file_id;
1402                 
1403                 file_id = g_open (filename, O_RDONLY, 0);
1404                 if (file_id != -1) {
1405                         TnyMimePart *mime_part;
1406                         TnyStream *stream;
1407                         const gchar *mime_type;
1408                         gchar *basename;
1409                         gchar *content_id;
1410                         
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 }