* src/modest-ui-actions.[ch]:
[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         gchar *markup;
664
665         /* Toolbar */
666         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
667         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
668
669         /* should we hide the toolbar? */
670         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
671                 gtk_widget_hide (parent_priv->toolbar);
672
673         /* Font color placeholder */
674         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
675         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
676
677         /* font color */
678         tool_item = GTK_WIDGET (gtk_tool_item_new ());
679         priv->font_color_button = hildon_color_button_new ();
680         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
681         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
682         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
683         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
684         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
685
686         /* Font size and face placeholder */
687         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
688         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
689         /* font_size */
690         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
691         priv->size_tool_button_label = gtk_label_new (NULL);
692         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
693         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
694                               size_text,"</span>", NULL);
695         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
696         g_free (markup);
697         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
698         sizes_menu = gtk_menu_new ();
699         priv->size_items_group = NULL;
700         radio_group = NULL;
701         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
702                 GtkWidget *size_menu_item;
703
704                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
705                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
706                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
707                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
708                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
709                 gtk_widget_show (size_menu_item);
710
711                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
712                         
713                 g_signal_connect (G_OBJECT (size_menu_item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
714                                   window);
715         }
716         priv->size_items_group = g_slist_reverse (priv->size_items_group);
717         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
718         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
719         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
720         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
721         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
722         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
723         priv->font_size_toolitem = tool_item;
724
725         /* font face */
726         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
727         priv->font_tool_button_label = gtk_label_new (NULL);
728         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
729         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
730         g_free(markup);
731         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
732         fonts_menu = gtk_menu_new ();
733         priv->font_items_group = NULL;
734         radio_group = NULL;
735         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
736                 GtkWidget *font_menu_item;
737                 GtkWidget *child_label;
738
739                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
740                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
741                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
742                                       wp_get_font_name (font_index), "</span>", NULL);
743                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
744                 g_free (markup);
745                 
746                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
747                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
748                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
749                 gtk_widget_show (font_menu_item);
750
751                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
752                         
753                 g_signal_connect (G_OBJECT (font_menu_item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
754                                   window);
755         }
756         priv->font_items_group = g_slist_reverse (priv->font_items_group);
757         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
758         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
759         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
760         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
761         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
762         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
763         priv->font_face_toolitem = tool_item;
764
765         /* Set expand and homogeneous for remaining items */
766         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
767         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
768         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
769         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
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         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
773         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
774         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
775
776
777 }
778
779
780
781 ModestWindow*
782 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
783 {
784         GObject *obj;
785         ModestWindowPrivate *parent_priv;
786         ModestMsgEditWindowPrivate *priv;
787         GtkActionGroup *action_group;
788         GError *error = NULL;
789         GdkPixbuf *window_icon = NULL;
790
791         g_return_val_if_fail (msg, NULL);
792         
793         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
794
795         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
796         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
797
798         parent_priv->ui_manager = gtk_ui_manager_new();
799         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
800         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
801
802         /* Add common actions */
803         gtk_action_group_add_actions (action_group,
804                                       modest_msg_edit_action_entries,
805                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
806                                       obj);
807         gtk_action_group_add_toggle_actions (action_group,
808                                              modest_msg_edit_toggle_action_entries,
809                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
810                                              obj);
811         gtk_action_group_add_radio_actions (action_group,
812                                             modest_msg_edit_alignment_radio_action_entries,
813                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
814                                             GTK_JUSTIFY_LEFT,
815                                             G_CALLBACK (modest_ui_actions_on_change_justify),
816                                             obj);
817         gtk_action_group_add_radio_actions (action_group,
818                                             modest_msg_edit_zoom_action_entries,
819                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
820                                             100,
821                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
822                                             obj);
823         gtk_action_group_add_radio_actions (action_group,
824                                             modest_msg_edit_priority_action_entries,
825                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
826                                             0,
827                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
828                                             obj);
829         gtk_action_group_add_radio_actions (action_group,
830                                             modest_msg_edit_file_format_action_entries,
831                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
832                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
833                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
834                                             obj);
835         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
836         g_object_unref (action_group);
837
838         /* Load the UI definition */
839         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml", &error);
840         if (error != NULL) {
841                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
842                 g_error_free (error);
843                 error = NULL;
844         }
845
846         /* Add accelerators */
847         gtk_window_add_accel_group (GTK_WINDOW (obj), 
848                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
849
850         /* Menubar */
851         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
852         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
853
854         /* Init window */
855         init_window (MODEST_MSG_EDIT_WINDOW(obj));
856
857         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
858                 
859         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
860         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
861
862         g_signal_connect (G_OBJECT(obj), "delete-event",
863                           G_CALLBACK(on_delete_event), obj);
864
865         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
866
867         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
868
869         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
870
871         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
872
873         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
874
875         /* Set window icon */
876         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
877         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
878         
879         return (ModestWindow*)obj;
880 }
881
882 static gint
883 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
884 {
885         GString **string_buffer = (GString **) user_data;
886
887         *string_buffer = g_string_append (*string_buffer, buffer);
888    
889         return 0;
890 }
891
892 static gchar *
893 get_formatted_data (ModestMsgEditWindow *edit_window)
894 {
895         ModestMsgEditWindowPrivate *priv;
896         GString *string_buffer = g_string_new ("");
897         
898         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
899
900         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
901
902         return g_string_free (string_buffer, FALSE);
903                                                                         
904 }
905
906 MsgData * 
907 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
908 {
909         MsgData *data;
910         const gchar *account_name;
911         GtkTextBuffer *buf;
912         GtkTextIter b, e;
913         ModestMsgEditWindowPrivate *priv;
914         
915         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
916
917         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
918                                                                         
919         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
920         g_return_val_if_fail (account_name, NULL);
921         
922         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));        
923         gtk_text_buffer_get_bounds (buf, &b, &e);
924         
925         /* don't free these (except from) */
926         data = g_slice_new0 (MsgData);
927         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
928                                                              account_name);
929         data->to      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->to_field));
930         data->cc      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->cc_field));
931         data->bcc     =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->bcc_field));
932         data->subject =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field));  
933         data->plain_body =  (gchar *) gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE);
934         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
935                 data->html_body = get_formatted_data (edit_window);
936         else
937                 data->html_body = NULL;
938         data->attachments = priv->attachments;
939         data->priority_flags = priv->priority_flags;
940
941         return data;
942 }
943
944 void 
945 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
946                                                       MsgData *data)
947 {
948         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
949
950         g_free (data->from);
951         g_free (data->html_body);
952         g_free (data->plain_body);
953         g_slice_free (MsgData, data);
954 }
955
956 ModestMsgEditFormat
957 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
958 {
959         gboolean rich_text;
960         ModestMsgEditWindowPrivate *priv = NULL;
961         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
962
963         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
964
965         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
966         if (rich_text)
967                 return MODEST_MSG_EDIT_FORMAT_HTML;
968         else
969                 return MODEST_MSG_EDIT_FORMAT_TEXT;
970 }
971
972 void
973 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
974                                    ModestMsgEditFormat format)
975 {
976         ModestMsgEditWindowPrivate *priv;
977
978         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
979         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
980
981         switch (format) {
982         case MODEST_MSG_EDIT_FORMAT_HTML:
983                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
984                 break;
985         case MODEST_MSG_EDIT_FORMAT_TEXT:
986                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
987                 break;
988         default:
989                 g_return_if_reached ();
990         }
991 }
992
993 ModestMsgEditFormatState *
994 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
995 {
996         ModestMsgEditFormatState *format_state = NULL;
997         ModestMsgEditWindowPrivate *priv;
998         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
999
1000         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1001         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1002
1003         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1004
1005         format_state = g_new0 (ModestMsgEditFormatState, 1);
1006         format_state->bold = buffer_format->bold&0x1;
1007         format_state->italics = buffer_format->italic&0x1;
1008         format_state->bullet = buffer_format->bullet&0x1;
1009         format_state->color = buffer_format->color;
1010         format_state->font_size = buffer_format->font_size;
1011         format_state->font_family = wp_get_font_name (buffer_format->font);
1012         format_state->justification = buffer_format->justification;
1013         g_free (buffer_format);
1014
1015         return format_state;
1016  
1017 }
1018
1019 void
1020 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1021                                          const ModestMsgEditFormatState *format_state)
1022 {
1023         ModestMsgEditWindowPrivate *priv;
1024         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1025         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1026         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1027         g_return_if_fail (format_state != NULL);
1028
1029         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1030         gtk_widget_grab_focus (priv->msg_body);
1031         buffer_format->bold = (format_state->bold != FALSE);
1032         buffer_format->italic = (format_state->italics != FALSE);
1033         buffer_format->color = format_state->color;
1034         buffer_format->font_size = format_state->font_size;
1035         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1036         buffer_format->justification = format_state->justification;
1037         buffer_format->bullet = format_state->bullet;
1038
1039         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1040
1041         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1042         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1043         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
1044         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1045         buffer_format->cs.font = (buffer_format->font != current_format->font);
1046         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1047         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1048
1049         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1050         if (buffer_format->cs.bold) {
1051                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1052         }
1053         if (buffer_format->cs.italic) {
1054                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1055         }
1056         if (buffer_format->cs.color) {
1057                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1058         }
1059         if (buffer_format->cs.font_size) {
1060                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
1061         }
1062         if (buffer_format->cs.justification) {
1063                 switch (buffer_format->justification) {
1064                 case GTK_JUSTIFY_LEFT:
1065                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1066                         break;
1067                 case GTK_JUSTIFY_CENTER:
1068                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1069                         break;
1070                 case GTK_JUSTIFY_RIGHT:
1071                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1072                         break;
1073                 default:
1074                         break;
1075                 }
1076                         
1077         }
1078         if (buffer_format->cs.font) {
1079                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
1080         }
1081         if (buffer_format->cs.bullet) {
1082                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet));
1083         }
1084 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1085         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1086
1087         g_free (current_format);
1088
1089 }
1090
1091 static void
1092 toggle_action_set_active_block_notify (GtkToggleAction *action,
1093                                        gboolean value)
1094 {
1095         GSList *proxies = NULL;
1096
1097         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1098              proxies != NULL; proxies = g_slist_next (proxies)) {
1099                 GtkWidget *widget = (GtkWidget *) proxies->data;
1100                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
1101         }
1102
1103         gtk_toggle_action_set_active (action, value);
1104
1105         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1106              proxies != NULL; proxies = g_slist_next (proxies)) {
1107                 GtkWidget *widget = (GtkWidget *) proxies->data;
1108                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
1109         }
1110 }
1111
1112 static void
1113 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1114 {
1115         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1116         GtkAction *action;
1117         ModestWindowPrivate *parent_priv;
1118         ModestMsgEditWindowPrivate *priv;
1119         GtkWidget *new_size_menuitem;
1120         GtkWidget *new_font_menuitem;
1121         
1122         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1123         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1124
1125         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1126                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1127                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1128                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1129         } else {
1130                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1131                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1132                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1133         }
1134
1135         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1136         
1137         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1138         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1139
1140         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1141         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1142
1143         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1144         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1145
1146         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1147                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1148                                          window);
1149         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1150         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1151                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1152                                            window);
1153
1154         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1155                                                       buffer_format->font_size))->data);
1156         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1157                 GtkWidget *label;
1158                 gchar *markup;
1159
1160                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1161                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1162                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1163                 g_free (markup);
1164                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1165                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1166                                                  window);
1167                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1168                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1169                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1170                                                    window);
1171         }
1172
1173         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1174                                                       buffer_format->font))->data);
1175         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1176                 GtkWidget *label;
1177                 gchar *markup;
1178
1179                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1180                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1181                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1182                 g_free (markup);
1183                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1184                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1185                                                  window);
1186                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1187                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1188                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1189                                                    window);
1190         }
1191
1192         g_free (buffer_format);
1193
1194 }
1195
1196
1197 void
1198 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1199 {
1200         
1201         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1202         ModestMsgEditWindowPrivate *priv;
1203         GtkWidget *dialog = NULL;
1204         gint response;
1205         const GdkColor *new_color = NULL;
1206         
1207         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1208         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1209         
1210 #ifdef MODEST_HILDON_VERSION_0  
1211         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1212         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1213 #else
1214         dialog = hildon_color_chooser_new ();
1215         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1216 #endif /*MODEST_HILDON_VERSION_0*/              
1217         g_free (buffer_format);
1218
1219         response = gtk_dialog_run (GTK_DIALOG (dialog));
1220         switch (response) {
1221         case GTK_RESPONSE_OK: {
1222 #ifdef MODEST_HILDON_VERSION_0
1223                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1224 #else
1225                 GdkColor col;
1226                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1227                 new_color = &col;
1228 #endif /*MODEST_HILDON_VERSION_0*/
1229         }
1230
1231         break;
1232         default:
1233                 break;
1234         }
1235         gtk_widget_destroy (dialog);
1236
1237         if (new_color != NULL)
1238                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1239
1240 }
1241
1242 void
1243 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1244 {
1245         
1246         ModestMsgEditWindowPrivate *priv;
1247         GtkWidget *dialog = NULL;
1248         gint response;
1249         GdkColor *old_color = NULL;
1250         const GdkColor *new_color = NULL;
1251         
1252         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1253         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1254         
1255 #ifdef MODEST_HILDON_VERSION_0  
1256         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1257         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1258 #else
1259         dialog = hildon_color_chooser_new ();
1260         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1261 #endif /*MODEST_HILDON_VERSION_9*/              
1262
1263         response = gtk_dialog_run (GTK_DIALOG (dialog));
1264         switch (response) {
1265         case GTK_RESPONSE_OK: {
1266 #ifdef MODEST_HILDON_VERSION_0
1267                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1268 #else
1269                 GdkColor col;
1270                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1271                 new_color = &col;
1272 #endif /*MODEST_HILDON_VERSION_0*/
1273           }
1274                 break;
1275         default:
1276                 break;
1277         }
1278         gtk_widget_destroy (dialog);
1279
1280         if (new_color != NULL)
1281                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1282
1283 }
1284
1285 void
1286 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1287 {
1288         
1289         ModestMsgEditWindowPrivate *priv;
1290         GtkWidget *dialog = NULL;
1291         gint response = 0;
1292         gchar *filename = NULL;
1293         
1294         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1295         
1296         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1297
1298         response = gtk_dialog_run (GTK_DIALOG (dialog));
1299         switch (response) {
1300         case GTK_RESPONSE_OK:
1301                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1302                 break;
1303         default:
1304                 break;
1305         }
1306         gtk_widget_destroy (dialog);
1307
1308         if (filename) {
1309                 GdkPixbuf *pixbuf = NULL;
1310                 GtkTextIter position;
1311                 GtkTextMark *insert_mark;
1312
1313                 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1314                 if (pixbuf) {
1315                         gint image_file_id;
1316                         GdkPixbufFormat *pixbuf_format;
1317
1318                         image_file_id = g_open (filename, O_RDONLY, 0);
1319                         pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
1320                         if ((image_file_id != -1)&&(pixbuf_format != NULL)) {
1321                                 TnyMimePart *image_part;
1322                                 TnyStream *image_stream;
1323                                 gchar **mime_types;
1324                                 gchar *mime_type;
1325                                 gchar *basename;
1326                                 gchar *content_id;
1327
1328                                 mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format);
1329                                 if ((mime_types != NULL) && (mime_types[0] != NULL)) {
1330                                         mime_type = mime_types[0];
1331                                 } else {
1332                                         mime_type = "image/unknown";
1333                                 }
1334                                 image_part = tny_platform_factory_new_mime_part
1335                                         (modest_runtime_get_platform_factory ());
1336                                 image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id));
1337
1338                                 tny_mime_part_construct_from_stream (image_part, image_stream, mime_type);
1339                                 g_strfreev (mime_types);
1340
1341                                 content_id = g_strdup_printf ("%d", priv->last_cid);
1342                                 tny_mime_part_set_content_id (image_part, content_id);
1343                                 g_free (content_id);
1344                                 priv->last_cid++;
1345
1346                                 basename = g_path_get_basename (filename);
1347                                 tny_mime_part_set_filename (image_part, basename);
1348                                 g_free (basename);
1349                                 
1350                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1351                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1352                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf);
1353                                 priv->attachments = g_list_prepend (priv->attachments, image_part);
1354                                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1355                                                                         image_part);
1356                                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1357                                 gtk_widget_show_all (priv->attachments_caption);
1358                         } else if (image_file_id == -1) {
1359                                 close (image_file_id);
1360                         }
1361                 }
1362         }
1363
1364
1365 }
1366
1367 void
1368 modest_msg_edit_window_attach_file (ModestMsgEditWindow *window)
1369 {
1370         
1371         ModestMsgEditWindowPrivate *priv;
1372         GtkWidget *dialog = NULL;
1373         gint response = 0;
1374         gchar *filename = NULL;
1375         
1376         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1377         
1378         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1379
1380         response = gtk_dialog_run (GTK_DIALOG (dialog));
1381         switch (response) {
1382         case GTK_RESPONSE_OK:
1383                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1384                 break;
1385         default:
1386                 break;
1387         }
1388         gtk_widget_destroy (dialog);
1389
1390         if (filename) {
1391                 gint file_id;
1392                 
1393                 file_id = g_open (filename, O_RDONLY, 0);
1394                 if (file_id != -1) {
1395                         TnyMimePart *mime_part;
1396                         TnyStream *stream;
1397                         const gchar *mime_type;
1398                         gchar *basename;
1399                         gchar *content_id;
1400                         
1401                         /* TODO: get mime type */
1402                         mime_type = gnome_vfs_get_file_mime_type_fast (filename, NULL);
1403                         mime_part = tny_platform_factory_new_mime_part
1404                                 (modest_runtime_get_platform_factory ());
1405                         stream = TNY_STREAM (tny_fs_stream_new (file_id));
1406                         
1407                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1408                         
1409                         content_id = g_strdup_printf ("%d", priv->last_cid);
1410                         tny_mime_part_set_content_id (mime_part, content_id);
1411                         g_free (content_id);
1412                         priv->last_cid++;
1413                         
1414                         basename = g_path_get_basename (filename);
1415                         tny_mime_part_set_filename (mime_part, basename);
1416                         g_free (basename);
1417                         
1418                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1419                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1420                                                                 mime_part);
1421                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1422                         gtk_widget_show_all (priv->attachments_caption);
1423                 } else if (file_id == -1) {
1424                         close (file_id);
1425                 }
1426         }
1427 }
1428
1429 void
1430 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1431                                           GList *att_list)
1432 {
1433         ModestMsgEditWindowPrivate *priv;
1434         gboolean clean_list = FALSE;
1435
1436         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1437         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1438
1439         if (att_list == NULL) {
1440                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1441                 clean_list = TRUE;
1442         }
1443
1444         if (att_list == NULL) {
1445                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1446         } else {
1447                 GtkWidget *confirmation_dialog = NULL;
1448                 gboolean dialog_response;
1449                 GList *node;
1450                 if (att_list->next == NULL) {
1451                         gchar *message = g_strdup_printf (_("emev_nc_delete_attachment"), 
1452                                                           tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
1453                         confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1454                         g_free (message);
1455                 } else {
1456                         confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), _("emev_nc_delete_attachments"));
1457                 }
1458                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1459                 gtk_widget_destroy (confirmation_dialog);
1460                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1461
1462                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1463                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1464                         const gchar *att_id;
1465                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1466
1467                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1468                                                                    mime_part);
1469                         att_id = tny_mime_part_get_content_id (mime_part);
1470                         if (att_id != NULL)
1471                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1472                                                                  att_id);
1473                         g_object_unref (mime_part);
1474                 }
1475         }
1476
1477         if (clean_list)
1478                 g_list_free (att_list);
1479 }
1480
1481 static void
1482 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1483                                             gpointer userdata)
1484 {
1485         ModestMsgEditWindowPrivate *priv;
1486         GdkColor *new_color;
1487         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1488         
1489 #ifdef MODEST_HILDON_VERSION_0  
1490         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1491 #else 
1492         GdkColor col;
1493         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1494         new_color = &col;
1495 #endif /*MODEST_HILDON_VERSION_0*/
1496
1497         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1498         
1499         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1500
1501 }
1502
1503 static void
1504 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1505                                     gpointer userdata)
1506 {
1507         ModestMsgEditWindowPrivate *priv;
1508         gint new_size_index;
1509         ModestMsgEditWindow *window;
1510         GtkWidget *label;
1511         
1512         window = MODEST_MSG_EDIT_WINDOW (userdata);
1513         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1514         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1515
1516         if (gtk_check_menu_item_get_active (menu_item)) {
1517                 gchar *markup;
1518
1519                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1520                 
1521                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1522
1523                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, 
1524                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
1525                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1526                 
1527                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1528                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1529                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1530                 g_free (markup);
1531         }
1532 }
1533
1534 static void
1535 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1536                                     gpointer userdata)
1537 {
1538         ModestMsgEditWindowPrivate *priv;
1539         gint new_font_index;
1540         ModestMsgEditWindow *window;
1541         GtkWidget *label;
1542         
1543         window = MODEST_MSG_EDIT_WINDOW (userdata);
1544         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1545         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1546
1547         if (gtk_check_menu_item_get_active (menu_item)) {
1548                 gchar *markup;
1549
1550                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1551                 
1552                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1553
1554                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1555                                                    (gpointer) new_font_index))
1556                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1557                 
1558                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1559                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1560                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1561                 g_free (markup);
1562         }
1563 }
1564
1565 static void
1566 modest_msg_edit_window_set_zoom (ModestWindow *window,
1567                                  gdouble zoom)
1568 {
1569         ModestMsgEditWindowPrivate *priv;
1570      
1571         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1572
1573         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1574         priv->zoom_level = zoom;
1575         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1576 }
1577
1578 static gdouble
1579 modest_msg_edit_window_get_zoom (ModestWindow *window)
1580 {
1581         ModestMsgEditWindowPrivate *priv;
1582      
1583         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1584
1585         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1586         return priv->zoom_level;
1587 }
1588
1589 static gboolean
1590 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1591 {
1592         ModestWindowPrivate *parent_priv;
1593         GtkRadioAction *zoom_radio_action;
1594         GSList *group, *node;
1595
1596         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1597         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1598                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1599
1600         group = gtk_radio_action_get_group (zoom_radio_action);
1601
1602         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1603                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_max_zoom_level"));
1604                 return FALSE;
1605         }
1606
1607         for (node = group; node != NULL; node = g_slist_next (node)) {
1608                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1609                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1610                         return TRUE;
1611                 }
1612         }
1613         return FALSE;
1614 }
1615
1616 static gboolean
1617 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1618 {
1619         ModestWindowPrivate *parent_priv;
1620         GtkRadioAction *zoom_radio_action;
1621         GSList *group, *node;
1622
1623         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1624         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1625                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1626
1627         group = gtk_radio_action_get_group (zoom_radio_action);
1628
1629         for (node = group; node != NULL; node = g_slist_next (node)) {
1630                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1631                         if (node->next != NULL) {
1632                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1633                                 return TRUE;
1634                         } else
1635                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_min_zoom_level"));
1636                         break;
1637                 }
1638         }
1639         return FALSE;
1640 }
1641
1642 static gboolean
1643 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1644 {
1645         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1646                 ModestWindowPrivate *parent_priv;
1647                 ModestWindowMgr *mgr;
1648                 gboolean is_fullscreen;
1649                 GtkAction *fs_toggle_action;
1650                 gboolean active;
1651
1652                 mgr = modest_runtime_get_window_mgr ();
1653                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1654
1655                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1656                 
1657                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1658                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1659                 if (is_fullscreen != active)
1660                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1661         }
1662
1663         return FALSE;
1664
1665 }
1666
1667 void
1668 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1669 {
1670         ModestWindowPrivate *parent_priv;
1671         GtkAction *fs_toggle_action;
1672         gboolean active;
1673
1674         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1675
1676         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1677         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1678         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1679 }
1680
1681 void
1682 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1683                                 gboolean show)
1684 {
1685         ModestMsgEditWindowPrivate *priv = NULL;
1686         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1687
1688         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1689         if (show)
1690                 gtk_widget_show (priv->cc_caption);
1691         else
1692                 gtk_widget_hide (priv->cc_caption);
1693 }
1694
1695 void
1696 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1697                                  gboolean show)
1698 {
1699         ModestMsgEditWindowPrivate *priv = NULL;
1700         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1701
1702         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1703         if (show)
1704                 gtk_widget_show (priv->bcc_caption);
1705         else
1706                 gtk_widget_hide (priv->bcc_caption);
1707 }
1708
1709 static void
1710 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
1711                                          ModestRecptEditor *editor)
1712 {
1713         ModestMsgEditWindowPrivate *priv;
1714
1715         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1716         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
1717         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1718
1719         if (editor == NULL) {
1720                 GtkWidget *view_focus;
1721                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
1722
1723                 /* This code should be kept in sync with ModestRecptEditor. The
1724                    textview inside the recpt editor is the one that really gets the
1725                    focus. As it's inside a scrolled window, and this one inside the
1726                    hbox recpt editor inherits from, we'll need to go up in the 
1727                    hierarchy to know if the text view is part of the recpt editor
1728                    or if it's a different text entry */
1729
1730                 if (gtk_widget_get_parent (view_focus)) {
1731                         GtkWidget *first_parent;
1732
1733                         first_parent = gtk_widget_get_parent (view_focus);
1734                         if (gtk_widget_get_parent (first_parent) && 
1735                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
1736                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
1737                         }
1738                 }
1739
1740                 if (editor == NULL)
1741                         editor = MODEST_RECPT_EDITOR (priv->to_field);
1742
1743         }
1744
1745         modest_address_book_select_addresses (editor);
1746
1747 }
1748
1749 void
1750 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
1751 {
1752         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1753
1754         modest_msg_edit_window_open_addressbook (window, NULL);
1755 }
1756
1757 static void
1758 modest_msg_edit_window_show_toolbar (ModestWindow *self,
1759                                      gboolean show_toolbar)
1760 {
1761         ModestWindowPrivate *parent_priv;
1762         
1763         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1764         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1765
1766         /* FIXME: we can not just use the code of
1767            modest_msg_edit_window_setup_toolbar because it has a
1768            mixture of both initialization and creation code. */
1769
1770         if (show_toolbar)
1771                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1772         else
1773                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1774 }
1775
1776 void
1777 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
1778                                            TnyHeaderFlags priority_flags)
1779 {
1780         ModestMsgEditWindowPrivate *priv;
1781
1782         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1783
1784         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1785         priority_flags = priority_flags & (TNY_HEADER_FLAG_HIGH_PRIORITY);
1786
1787         if (priv->priority_flags != priority_flags) {
1788
1789                 priv->priority_flags = priority_flags;
1790
1791                 switch (priority_flags) {
1792                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
1793                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
1794                         gtk_widget_show (priv->priority_icon);
1795                         break;
1796                 case TNY_HEADER_FLAG_LOW_PRIORITY:
1797                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
1798                         gtk_widget_show (priv->priority_icon);
1799                         break;
1800                 default:
1801                         gtk_widget_hide (priv->priority_icon);
1802                         break;
1803                 }
1804         }
1805 }
1806
1807 void
1808 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
1809                                         gint file_format)
1810 {
1811         ModestMsgEditWindowPrivate *priv;
1812         gint current_format;
1813
1814         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1815
1816         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1817
1818         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
1819                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
1820
1821         if (current_format != file_format) {
1822                 switch (file_format) {
1823                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
1824                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1825                         break;
1826                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
1827                 {
1828                         GtkWidget *dialog;
1829                         gint response;
1830                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
1831                         response = gtk_dialog_run (GTK_DIALOG (dialog));
1832                         gtk_widget_destroy (dialog);
1833                         if (response == GTK_RESPONSE_OK)
1834                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1835                 }
1836                         break;
1837                 }
1838                 update_dimmed (window);
1839         }
1840 }
1841
1842 void
1843 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
1844 {
1845         GtkWidget *dialog;
1846         ModestMsgEditWindowPrivate *priv;
1847         WPTextBufferFormat oldfmt, fmt;
1848         gint old_position = 0;
1849         gint response = 0;
1850         gint position = 0;
1851         gint font_size;
1852         GdkColor *color = NULL;
1853         gboolean bold, bold_set, italic, italic_set;
1854         gboolean underline, underline_set;
1855         gboolean strikethrough, strikethrough_set;
1856         gboolean position_set;
1857         gboolean font_size_set, font_set, color_set;
1858         gchar *font_name;
1859
1860         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1861         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1862         
1863         dialog = hildon_font_selection_dialog_new (NULL, NULL);
1864
1865         /* First we get the currently selected font information */
1866         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
1867         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
1868
1869         switch (oldfmt.text_position) {
1870         case TEXT_POSITION_NORMAL:
1871                 old_position = 0;
1872                 break;
1873         case TEXT_POSITION_SUPERSCRIPT:
1874                 old_position = 1;
1875                 break;
1876         default:
1877                 old_position = -1;
1878                 break;
1879         }
1880
1881         g_object_set (G_OBJECT (dialog),
1882                       "bold", oldfmt.bold != FALSE,
1883                       "bold-set", !oldfmt.cs.bold,
1884                       "underline", oldfmt.underline != FALSE,
1885                       "underline-set", !oldfmt.cs.underline,
1886                       "italic", oldfmt.italic != FALSE,
1887                       "italic-set", !oldfmt.cs.italic,
1888                       "strikethrough", oldfmt.strikethrough != FALSE,
1889                       "strikethrough-set", !oldfmt.cs.strikethrough,
1890                       "color", &oldfmt.color,
1891                       "color-set", !oldfmt.cs.color,
1892                       "size", wp_font_size[oldfmt.font_size],
1893                       "size-set", !oldfmt.cs.font_size,
1894                       "position", old_position,
1895                       "position-set", !oldfmt.cs.text_position,
1896                       "family", wp_get_font_name (oldfmt.font),
1897                       "family-set", !oldfmt.cs.font,
1898                       NULL);
1899
1900         gtk_widget_show_all (dialog);
1901         response = gtk_dialog_run (GTK_DIALOG (dialog));
1902         if (response == GTK_RESPONSE_OK) {
1903
1904                 g_object_get( dialog,
1905                               "bold", &bold,
1906                               "bold-set", &bold_set,
1907                               "underline", &underline,
1908                               "underline-set", &underline_set,
1909                               "italic", &italic,
1910                               "italic-set", &italic_set,
1911                               "strikethrough", &strikethrough,
1912                               "strikethrough-set", &strikethrough_set,
1913                               "color", &color,
1914                               "color-set", &color_set,
1915                               "size", &font_size,
1916                               "size-set", &font_size_set,
1917                               "family", &font_name,
1918                               "family-set", &font_set,
1919                               "position", &position,
1920                               "position-set", &position_set,
1921                               NULL );
1922                 
1923         }       
1924
1925         gtk_widget_destroy (dialog);
1926         
1927         if (response == GTK_RESPONSE_OK) {
1928                 memset(&fmt, 0, sizeof(fmt));
1929                 if (bold_set) {
1930                         fmt.bold = bold;
1931                         fmt.cs.bold = TRUE;
1932                 }
1933                 if (italic_set) {
1934                         fmt.italic = italic;
1935                         fmt.cs.italic = TRUE;
1936                 }
1937                 if (underline_set) {
1938                         fmt.underline = underline;
1939                         fmt.cs.underline = TRUE;
1940                 }
1941                 if (strikethrough_set) {
1942                         fmt.strikethrough = strikethrough;
1943                         fmt.cs.strikethrough = TRUE;
1944                 }
1945                 if (position_set) {
1946                         fmt.text_position =
1947                                 ( position == 0 )
1948                                 ? TEXT_POSITION_NORMAL
1949                                 : ( ( position == 1 )
1950                                     ? TEXT_POSITION_SUPERSCRIPT
1951                                     : TEXT_POSITION_SUBSCRIPT );
1952                         fmt.cs.text_position = TRUE;
1953                 }
1954                 if (color_set) {
1955                         fmt.color = *color;
1956                         fmt.cs.color = TRUE;
1957                 }
1958                 gdk_color_free(color);
1959                 if (font_set) {
1960                         fmt.font = wp_get_font_index(font_name,
1961                                                      DEFAULT_FONT);
1962                         fmt.cs.font = TRUE;
1963                 }
1964                 g_free(font_name);
1965                 if (font_size_set) {
1966                         fmt.font_size = wp_get_font_size_index(
1967                                 font_size, DEFAULT_FONT_SIZE);
1968                         fmt.cs.font_size = TRUE;
1969                 }
1970                 gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
1971                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
1972         }
1973
1974 }
1975
1976 void
1977 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
1978 {
1979         ModestMsgEditWindowPrivate *priv;
1980
1981         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1982         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1983         
1984         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
1985
1986         update_dimmed (window);
1987
1988 }
1989
1990 static void
1991 update_dimmed (ModestMsgEditWindow *window)
1992 {
1993         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1994         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1995         GtkAction *action;
1996         GtkWidget *widget;
1997         gboolean rich_text;
1998         gboolean editor_focused;
1999
2000         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2001         editor_focused = gtk_widget_is_focus (priv->msg_body);
2002
2003         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2004         gtk_action_set_sensitive (action, rich_text && editor_focused);
2005         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2006         gtk_action_set_sensitive (action, rich_text && editor_focused);
2007         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2008         gtk_action_set_sensitive (action, rich_text && editor_focused);
2009         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2010         gtk_action_set_sensitive (action, rich_text && editor_focused);
2011         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2012         gtk_action_set_sensitive (action, rich_text && editor_focused);
2013         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2014         gtk_action_set_sensitive (action, rich_text && editor_focused);
2015         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2016         gtk_action_set_sensitive (action, rich_text && editor_focused);
2017         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2018         gtk_action_set_sensitive (action, rich_text && editor_focused);
2019         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2020         gtk_action_set_sensitive (action, rich_text && editor_focused);
2021         widget = priv->font_color_button;
2022         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2023         widget = priv->font_size_toolitem;
2024         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2025         widget = priv->font_face_toolitem;
2026         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2027 }
2028
2029 static void
2030 setup_insensitive_handlers (ModestMsgEditWindow *window)
2031 {
2032         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2033         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2034         GtkWidget *widget;
2035
2036         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2037         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2038         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2039         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2040
2041         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2042         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2043         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2044         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2045         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2046         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2047         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2048         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2049         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2050         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2051         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2052         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2053         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2054         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2055         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2056         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2057         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2058         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2059         widget = priv->font_color_button;
2060         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2061         widget = priv->font_size_toolitem;
2062         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2063         widget = priv->font_face_toolitem;
2064         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2065
2066 }
2067
2068 static void  
2069 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2070 {
2071         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2072         GtkAction *action;
2073
2074         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2075         gtk_action_set_sensitive (action, can_undo);
2076 }
2077
2078 static void
2079 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2080 {
2081         GtkTextIter iter;
2082         GtkTextIter match_start, match_end;
2083
2084         if (image_id == NULL)
2085                 return;
2086
2087         gtk_text_buffer_get_start_iter (buffer, &iter);
2088
2089         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2090                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2091                 GSList *node;
2092                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2093                         GtkTextTag *tag = (GtkTextTag *) node->data;
2094                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2095                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2096                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2097                                         gint offset;
2098                                         gtk_text_iter_get_offset (&match_start);
2099                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2100                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2101                                 }
2102                         }
2103                 }
2104         }
2105 }
2106
2107 static void
2108 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2109 {
2110         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2111         GtkTextIter real_start, real_end;
2112         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2113
2114         if (gtk_text_iter_compare (start, end) > 0) {
2115                 real_start = *end;
2116                 real_end = *start;
2117         } else {
2118                 real_start = *start;
2119                 real_end = *end;
2120         }
2121         do {
2122                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2123                 GSList *node;
2124                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2125                         GtkTextTag *tag = (GtkTextTag *) node->data;
2126                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2127                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2128
2129                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2130                                                                                  image_id);
2131                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2132                         }
2133                 }
2134         } while (gtk_text_iter_forward_char (&real_start)&&
2135                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2136 }
2137
2138 static gboolean
2139 msg_body_focus (GtkWidget *focus,
2140                 GdkEventFocus *event,
2141                 gpointer userdata)
2142 {
2143         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2144         return FALSE;
2145 }
2146
2147 static void
2148 to_field_changed (GtkTextBuffer *buffer,
2149                   ModestMsgEditWindow *editor)
2150 {
2151         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2152         GtkAction *action;
2153
2154         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2155         gtk_action_set_sensitive (action, gtk_text_buffer_get_char_count (buffer) != 0);
2156         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2157         gtk_action_set_sensitive (action, gtk_text_buffer_get_char_count (buffer) != 0);
2158 }
2159
2160 static void  
2161 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2162 {
2163         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2164 }
2165
2166 static void
2167 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2168 {
2169         gboolean rich_text, editor_focused;
2170
2171         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2172         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2173         editor_focused = gtk_widget_is_focus (priv->msg_body);
2174
2175         if (!rich_text)
2176                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2177         else if (!editor_focused)
2178                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2179 }
2180
2181 static void
2182 reset_modified (ModestMsgEditWindow *editor)
2183 {
2184         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2185         GtkTextBuffer *buffer;
2186
2187         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2188         gtk_text_buffer_set_modified (buffer, FALSE);
2189         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2190         gtk_text_buffer_set_modified (buffer, FALSE);
2191         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2192         gtk_text_buffer_set_modified (buffer, FALSE);
2193         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2194 }
2195
2196 static gboolean
2197 is_modified (ModestMsgEditWindow *editor)
2198 {
2199         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2200         GtkTextBuffer *buffer;
2201
2202         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2203         if (gtk_text_buffer_get_modified (buffer))
2204                 return TRUE;
2205         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2206         if (gtk_text_buffer_get_modified (buffer))
2207                 return TRUE;
2208         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2209         if (gtk_text_buffer_get_modified (buffer))
2210                 return TRUE;
2211         if (gtk_text_buffer_get_modified (priv->text_buffer))
2212                 return TRUE;
2213
2214         return FALSE;
2215 }
2216
2217 gboolean
2218 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2219 {
2220         ModestMsgEditWindowPrivate *priv = NULL;
2221
2222         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2223         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2224
2225         /* check if there's no recipient added */
2226         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2227             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2228             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2229                 /* no recipient contents, then select contacts */
2230                 modest_msg_edit_window_open_addressbook (window, NULL);
2231                 return FALSE;
2232         }
2233
2234         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2235                 return FALSE;
2236         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2237                 return FALSE;
2238         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2239                 return FALSE;
2240
2241         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2242
2243         return TRUE;
2244
2245 }
2246
2247 static void
2248 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2249                                                ModestMsgEditWindow *window)
2250 {
2251         modest_msg_edit_window_attach_file (window);
2252 }