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