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