1294512498d5dd22f81bc1a6b760f1a9abcdc517
[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-tny-folder.h"
59 #include "modest-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
65
66 #include "modest-hildon-includes.h"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-color-chooser.h>
69 #endif
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #ifdef MODEST_HAVE_HILDON0_WIDGETS
72 #include <libgnomevfs/gnome-vfs-mime-utils.h>
73 #else
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #endif
76 #include "modest-maemo-utils.h"
77
78
79 #define DEFAULT_FONT_SIZE 3
80 #define DEFAULT_FONT 2
81 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
82 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
83 #define DEFAULT_MAIN_VBOX_SPACING 6
84 #define SUBJECT_MAX_LENGTH 1000
85 #define IMAGE_MAX_WIDTH 640
86 #define DEFAULT_FONT_SCALE 1.5
87
88 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
89 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
90 static void  modest_msg_edit_window_finalize     (GObject *obj);
91
92 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
93 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
95 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
97 static void  reset_modified (ModestMsgEditWindow *editor);
98
99 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
100 static void  text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata);
101 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
102 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
103 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
104 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
105 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
106                                                          gpointer userdata);
107 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
108                                                  gpointer userdata);
109 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
110                                                  gpointer userdata);
111 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
112 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
113                                                            GdkEventWindowState *event, 
114                                                            gpointer userdata);
115 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
116                                                      ModestRecptEditor *editor);
117 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
118                                                            ModestMsgEditWindow *window);
119
120 /* ModestWindow methods implementation */
121 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
122 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
123 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
124 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
125 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
126                                                    gboolean show_toolbar);
127 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
128                                                            GdkEvent *event,
129                                                            ModestMsgEditWindow *window);
130 static void modest_msg_edit_window_system_clipboard_owner_change (GtkClipboard *clipboard,
131                                                                   GdkEvent *event,
132                                                                   ModestMsgEditWindow *window);
133 static void update_window_title (ModestMsgEditWindow *window);
134 static void update_dimmed (ModestMsgEditWindow *window);
135 static void update_paste_dimming (ModestMsgEditWindow *window);
136 static void update_select_all_dimming (ModestMsgEditWindow *window);
137 static void update_zoom_dimming (ModestMsgEditWindow *window);
138
139 /* Find toolbar */
140 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
141                                                         ModestMsgEditWindow *window);
142 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
143                                                        ModestMsgEditWindow *window);
144 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
145                                                           const gchar *str,
146                                                           GtkTextIter *match_start,
147                                                           GtkTextIter *match_end);
148                                                           
149
150
151 /* static gboolean */
152 /* on_key_pressed (GtkWidget *self, */
153 /*              GdkEventKey *event, */
154 /*              gpointer user_data); */
155
156 static void edit_menu_activated (GtkAction *action,
157                                  gpointer userdata);
158 static void view_menu_activated (GtkAction *action,
159                                  gpointer userdata);
160
161 /* list my signals */
162 enum {
163         /* MY_SIGNAL_1, */
164         /* MY_SIGNAL_2, */
165         LAST_SIGNAL
166 };
167
168 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
169 struct _ModestMsgEditWindowPrivate {
170         GtkWidget   *msg_body;
171         GtkWidget   *header_box;
172         
173         ModestPairList *from_field_protos;
174         GtkWidget   *from_field;
175         
176         GtkWidget   *to_field;
177         GtkWidget   *cc_field;
178         GtkWidget   *bcc_field;
179         GtkWidget   *subject_field;
180         GtkWidget   *attachments_view;
181         GtkWidget   *priority_icon;
182         GtkWidget   *add_attachment_button;
183
184         GtkWidget   *cc_caption;
185         GtkWidget   *bcc_caption;
186         GtkWidget   *attachments_caption;
187
188         GtkTextBuffer *text_buffer;
189
190         GtkWidget   *font_size_toolitem;
191         GtkWidget   *font_face_toolitem;
192         GtkWidget   *font_color_button;
193         GSList      *font_items_group;
194         GtkWidget   *font_tool_button_label;
195         GSList      *size_items_group;
196         GtkWidget   *size_tool_button_label;
197         
198         GtkWidget   *find_toolbar;
199         gchar       *last_search;
200
201         GtkWidget   *scroll;
202         GtkWidget   *scroll_area;
203
204         gint last_cid;
205         GList *attachments;
206
207         TnyHeaderFlags priority_flags;
208
209         gdouble zoom_level;
210         
211         gulong      clipboard_change_handler_id;
212         gulong      system_clipboard_change_handler_id;
213
214         TnyMsg      *draft_msg;
215         gboolean    sent;
216 };
217
218 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
219                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
220                                                     ModestMsgEditWindowPrivate))
221 /* globals */
222 static GtkWindowClass *parent_class = NULL;
223
224 /* uncomment the following if you have defined any signals */
225 /* static guint signals[LAST_SIGNAL] = {0}; */
226
227 GType
228 modest_msg_edit_window_get_type (void)
229 {
230         static GType my_type = 0;
231         if (!my_type) {
232                 static const GTypeInfo my_info = {
233                         sizeof(ModestMsgEditWindowClass),
234                         NULL,           /* base init */
235                         NULL,           /* base finalize */
236                         (GClassInitFunc) modest_msg_edit_window_class_init,
237                         NULL,           /* class finalize */
238                         NULL,           /* class data */
239                         sizeof(ModestMsgEditWindow),
240                         1,              /* n_preallocs */
241                         (GInstanceInitFunc) modest_msg_edit_window_init,
242                         NULL
243                 };
244                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
245                                                   "ModestMsgEditWindow",
246                                                   &my_info, 0);
247
248                 wp_text_buffer_library_init ();
249         }
250         return my_type;
251 }
252
253 static void
254 save_state (ModestWindow *self)
255 {
256         modest_widget_memory_save (modest_runtime_get_conf(),
257                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
258 }
259
260
261 static void
262 restore_settings (ModestMsgEditWindow *self)
263 {
264         modest_widget_memory_restore (modest_runtime_get_conf(),
265                                       G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
266 }
267
268
269 static void
270 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
271 {
272         GObjectClass *gobject_class;
273         ModestWindowClass *modest_window_class;
274         gobject_class = (GObjectClass*) klass;
275         modest_window_class = (ModestWindowClass*) klass;
276
277         parent_class            = g_type_class_peek_parent (klass);
278         gobject_class->finalize = modest_msg_edit_window_finalize;
279
280         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
281         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
282         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
283         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
284         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
285         modest_window_class->save_state_func = save_state;
286
287         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
288
289
290 }
291
292 static void
293 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
294 {
295         ModestMsgEditWindowPrivate *priv;
296         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
297
298         priv->msg_body      = NULL;
299         priv->from_field    = NULL;
300         priv->to_field      = NULL;
301         priv->cc_field      = NULL;
302         priv->bcc_field     = NULL;
303         priv->subject_field = NULL;
304         priv->attachments   = NULL;
305         priv->last_cid      = 0;
306         priv->zoom_level    = 1.0;
307
308         priv->cc_caption    = NULL;
309         priv->bcc_caption    = NULL;
310
311         priv->priority_flags = 0;
312
313         priv->find_toolbar = NULL;
314         priv->last_search = NULL;
315
316         priv->draft_msg = NULL;
317         priv->clipboard_change_handler_id = 0;
318         priv->system_clipboard_change_handler_id = 0;
319         priv->sent = FALSE;
320 }
321
322
323 /* FIXME: this is a dup from the one in gtk/ */
324
325 /** 
326  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
327  */
328 static ModestPairList*
329 get_transports (void)
330 {
331         GSList *transports = NULL;
332         
333         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
334         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
335                                                              TRUE /* only enabled accounts. */); 
336                                                 
337         GSList *cursor = accounts;
338         while (cursor) {
339                 gchar *account_name = cursor->data;
340                 gchar *from_string  = NULL;
341                 if (account_name) {
342                         from_string = modest_account_mgr_get_from_string (account_mgr,
343                                                                           account_name);
344                 }
345                 
346                 if (from_string && account_name) {
347                         gchar *name = account_name;
348                         ModestPair *pair = modest_pair_new ((gpointer) name,
349                                                 (gpointer) from_string , TRUE);
350                         transports = g_slist_prepend (transports, pair);
351                 }
352                 
353                 cursor = cursor->next;
354         }
355         g_slist_free (accounts); /* only free the accounts, not the elements,
356                                   * because they are used in the pairlist */
357         return transports;
358 }
359
360
361 static void
362 init_window (ModestMsgEditWindow *obj)
363 {
364         GtkWidget *from_caption, *to_caption, *subject_caption;
365         GtkWidget *main_vbox;
366         ModestMsgEditWindowPrivate *priv;
367
368         GtkSizeGroup *size_group;
369         GtkWidget *frame;
370         GtkWidget *subject_box;
371         GtkWidget *attachment_icon;
372         GtkWidget *window_box;
373
374         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
375
376         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
377
378         /* Note: This ModestPairList* must exist for as long as the combo
379          * that uses it, because the ModestComboBox uses the ID opaquely, 
380          * so it can't know how to manage its memory. */ 
381         priv->from_field_protos = get_transports ();
382
383         priv->from_field    = modest_combo_box_new (priv->from_field_protos, g_str_equal);
384
385         priv->to_field      = modest_recpt_editor_new ();
386         priv->cc_field      = modest_recpt_editor_new ();
387         priv->bcc_field     = modest_recpt_editor_new ();
388         subject_box = gtk_hbox_new (FALSE, 0);
389         priv->priority_icon = gtk_image_new ();
390         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
391         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
392         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
393                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
394         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
395         priv->add_attachment_button = gtk_button_new ();
396         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
397         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
398         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
399         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
400         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
401         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
402         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
403         priv->attachments_view = modest_attachments_view_new (NULL);
404         
405         priv->header_box = gtk_vbox_new (FALSE, 0);
406         
407         from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
408         to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
409         priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
410         priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
411         subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
412         priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
413         g_object_unref (size_group);
414
415         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
416         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
417         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
418         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
419         gtk_size_group_add_widget (size_group, priv->subject_field);
420         gtk_size_group_add_widget (size_group, priv->attachments_view);
421         g_object_unref (size_group);
422
423         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
424         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
425         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
426         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
427         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
428         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
429         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
430
431
432         priv->msg_body = wp_text_view_new ();
433         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
434         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
435         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
436         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
437         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
438         gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
439
440         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
441
442         priv->find_toolbar = hildon_find_toolbar_new (NULL);
443         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
444
445 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
446
447         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
448                           G_CALLBACK (text_buffer_refresh_attributes), obj);
449         g_signal_connect (G_OBJECT (priv->text_buffer), "delete-range",
450                           G_CALLBACK (text_buffer_delete_range), obj);
451         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
452                           G_CALLBACK (text_buffer_can_undo), obj);
453         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
454                           G_CALLBACK (text_buffer_can_redo), obj);
455         g_signal_connect (G_OBJECT (obj), "window-state-event",
456                           G_CALLBACK (modest_msg_edit_window_window_state_event),
457                           NULL);
458         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
459                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
460         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
461                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
462         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
463                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
464
465         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
466                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
467
468         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
469                           G_CALLBACK (msg_body_focus), obj);
470         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
471                           G_CALLBACK (msg_body_focus), obj);
472         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
473                           "changed", G_CALLBACK (recpt_field_changed), obj);
474         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
475                           "changed", G_CALLBACK (recpt_field_changed), obj);
476         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
477                           "changed", G_CALLBACK (recpt_field_changed), obj);
478         recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
479         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
480
481         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
482         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
483
484         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
485         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
486         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
487         
488         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
489
490         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
491         frame = gtk_frame_new (NULL);
492         gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
493
494         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
495         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
496         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
497         
498         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL)) {
499                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
500                 gtk_widget_hide (priv->cc_caption);
501         }
502         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL)) {
503                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
504                 gtk_widget_hide (priv->bcc_caption);
505         }
506
507         window_box = gtk_vbox_new (FALSE, 0);
508         gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
509         gtk_box_pack_end (GTK_BOX (window_box), priv->find_toolbar, FALSE, FALSE, 0);
510         gtk_container_add (GTK_CONTAINER(obj), window_box);
511         priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
512         gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
513         
514         /*
515          TODO: scroll_area was never instantiated.
516          Stop building without warnings-as-errors. murrayc.
517         gtk_container_set_focus_vadjustment (GTK_CONTAINER (scroll_area), 
518                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
519         */
520
521         priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
522                                                               G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
523         priv->system_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
524                                                               G_CALLBACK (modest_msg_edit_window_system_clipboard_owner_change), obj);
525 }
526         
527
528
529 static void
530 modest_msg_edit_window_finalize (GObject *obj)
531 {
532         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
533
534         if (priv->clipboard_change_handler_id > 0) {
535                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), priv->clipboard_change_handler_id);
536                 priv->clipboard_change_handler_id = 0;
537         }
538         
539         if (priv->system_clipboard_change_handler_id > 0) {
540                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
541                                              priv->system_clipboard_change_handler_id);
542                 priv->system_clipboard_change_handler_id = 0;
543         }
544         
545         if (priv->draft_msg != NULL) {
546                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
547                 if (TNY_IS_HEADER (header)) {
548                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
549                         modest_window_mgr_unregister_header (mgr, header);
550                 }
551                 g_object_unref (priv->draft_msg);
552                 priv->draft_msg = NULL;
553         }
554
555         /* This had to stay alive for as long as the combobox that used it: */
556         modest_pair_list_free (priv->from_field_protos);
557         
558         G_OBJECT_CLASS(parent_class)->finalize (obj);
559 }
560
561 static GtkWidget *
562 menubar_to_menu (GtkUIManager *ui_manager)
563 {
564         GtkWidget *main_menu;
565         GtkWidget *menubar;
566         GList *iter;
567
568         /* Create new main menu */
569         main_menu = gtk_menu_new();
570
571         /* Get the menubar from the UI manager */
572         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
573
574         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
575         while (iter) {
576                 GtkWidget *menu;
577
578                 menu = GTK_WIDGET (iter->data);
579                 gtk_widget_reparent(menu, main_menu);
580
581                 iter = g_list_next (iter);
582         }
583         return main_menu;
584 }
585
586
587 static void
588 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
589 {
590         TnyHeader *header;
591         const gchar *to, *cc, *bcc, *subject;
592         gchar *body;
593         ModestMsgEditWindowPrivate *priv;
594         GtkTextIter iter;
595         TnyHeaderFlags priority_flags;
596         TnyFolder *msg_folder;
597         
598         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
599         g_return_if_fail (TNY_IS_MSG (msg));
600
601         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
602
603         header = tny_msg_get_header (msg);
604         to      = tny_header_get_to (header);
605         cc      = tny_header_get_cc (header);
606         bcc     = tny_header_get_bcc (header);
607         subject = tny_header_get_subject (header);
608         priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
609
610         if (to)
611                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
612         if (cc) {
613                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
614                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
615                 gtk_widget_show (priv->cc_caption);
616         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
617                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
618                 gtk_widget_hide (priv->cc_caption);
619         }
620         if (bcc) {
621                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
622                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
623                 gtk_widget_show (priv->bcc_caption);
624         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
625                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
626                 gtk_widget_hide (priv->bcc_caption);
627         } 
628         if (subject)
629                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
630         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
631                                                    priority_flags);
632
633         update_window_title (self);
634
635         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
636         body = modest_tny_msg_get_body (msg, TRUE);
637
638         if ((body == NULL)||(body[0] == '\0')) {
639                 g_free (body);
640                 body = modest_text_utils_convert_to_html ("");
641         }
642         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
643         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
644                                             (gchar *) body,
645                                             strlen (body));
646         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
647         g_free (body);
648
649         /* Get the default format required from configuration */
650         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
651                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
652         }
653
654         /* Set the default focus depending on having already a To: field or not */
655         if ((!to)||(*to == '\0')) {
656                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
657         } else {
658                 gtk_widget_grab_focus (priv->msg_body);
659         }
660
661         /* TODO: lower priority, select in the From: combo to the
662            value that comes from msg <- not sure, should it be
663            allowed? */
664         
665         /* Add attachments to the view */
666         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
667         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
668         if (priv->attachments == NULL) {
669                 gtk_widget_hide (priv->attachments_caption);
670         } else {
671                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
672                 gtk_widget_show_all (priv->attachments_caption);
673         }
674
675         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
676         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
677
678         reset_modified (self);
679
680         update_dimmed (self);
681         text_buffer_can_undo (priv->text_buffer, FALSE, self);
682         text_buffer_can_redo (priv->text_buffer, FALSE, self);
683
684         /* we should set a reference to the incoming message if it is a draft */
685         msg_folder = tny_msg_get_folder (msg);
686         if (msg_folder) {
687                 if (modest_tny_folder_is_local_folder (msg_folder) &&
688                     modest_tny_folder_get_local_folder_type (msg_folder) == TNY_FOLDER_TYPE_DRAFTS)
689                         priv->draft_msg = g_object_ref(msg);
690                 g_object_unref (msg_folder);
691         }
692 }
693
694 static void
695 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
696                                 gpointer data)
697 {
698         GList *item_children, *node;
699         GtkWidget *bin_child;
700
701         bin_child = gtk_bin_get_child (GTK_BIN(item));
702
703         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
704         
705         for (node = item_children; node != NULL; node = g_list_next (node)) {
706                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
707                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
708                 }
709         }
710         g_list_free (item_children);
711 }
712
713 static void
714 menu_tool_button_dont_expand (GtkMenuToolButton *item)
715 {
716         GtkWidget *box;
717         GList *item_children, *node;
718
719         box = gtk_bin_get_child (GTK_BIN (item));
720         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
721         item_children = gtk_container_get_children (GTK_CONTAINER (box));
722         
723         for (node = item_children; node != NULL; node = g_list_next (node)) {
724                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
725                 if (GTK_IS_TOGGLE_BUTTON (node->data))
726                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
727                 else if (GTK_IS_BUTTON (node->data))
728                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
729         }
730         g_list_free (item_children);
731 }
732
733
734 static void
735 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
736 {
737         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
738         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
739         GtkWidget *placeholder;
740         GtkWidget *tool_item;
741         gint insert_index;
742         gchar size_text[5];
743         gint size_index;
744         gint font_index;
745         GtkWidget *sizes_menu;
746         GtkWidget *fonts_menu;
747         GSList *radio_group = NULL;
748         GSList *node = NULL;
749         gchar *markup;
750
751         /* Toolbar */
752         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
753         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
754
755         /* should we hide the toolbar? */
756         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
757                 gtk_widget_hide (parent_priv->toolbar);
758
759         /* Font color placeholder */
760         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
761         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
762
763         /* font color */
764         tool_item = GTK_WIDGET (gtk_tool_item_new ());
765         priv->font_color_button = hildon_color_button_new ();
766         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
767         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
768         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
769         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
770         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
771         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
772         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
773
774         /* Font size and face placeholder */
775         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
776         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
777         /* font_size */
778         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
779         priv->size_tool_button_label = gtk_label_new (NULL);
780         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
781         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
782                               size_text,"</span>", NULL);
783         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
784         g_free (markup);
785         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
786         sizes_menu = gtk_menu_new ();
787         priv->size_items_group = NULL;
788         radio_group = NULL;
789         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
790                 GtkWidget *size_menu_item;
791
792                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
793                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
794                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
795                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
796                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
797                 gtk_widget_show (size_menu_item);
798
799                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
800                         
801         }
802
803         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
804                 GtkWidget *item = (GtkWidget *) node->data;
805                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
806                                   window);
807         }
808
809         priv->size_items_group = g_slist_reverse (priv->size_items_group);
810         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
811         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
812         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
813         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
814         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
815         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
816         priv->font_size_toolitem = tool_item;
817
818         /* font face */
819         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
820         priv->font_tool_button_label = gtk_label_new (NULL);
821         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
822         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
823         g_free(markup);
824         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
825         fonts_menu = gtk_menu_new ();
826         priv->font_items_group = NULL;
827         radio_group = NULL;
828         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
829                 GtkWidget *font_menu_item;
830                 GtkWidget *child_label;
831
832                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
833                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
834                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
835                                       wp_get_font_name (font_index), "</span>", NULL);
836                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
837                 g_free (markup);
838                 
839                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
840                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
841                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
842                 gtk_widget_show (font_menu_item);
843
844                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
845                         
846         }
847         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
848                 GtkWidget *item = (GtkWidget *) node->data;
849                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
850                                   window);
851         }
852         priv->font_items_group = g_slist_reverse (priv->font_items_group);
853         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
854         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
855         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
856         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
857         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
858         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
859         priv->font_face_toolitem = tool_item;
860
861         /* Set expand and homogeneous for remaining items */
862         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
863         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
864         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
865         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
866         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
867         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
868         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
869         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
870         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
871
872
873 }
874
875
876
877 ModestWindow*
878 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
879 {
880         GObject *obj;
881         ModestWindowPrivate *parent_priv;
882         ModestMsgEditWindowPrivate *priv;
883         GtkActionGroup *action_group;
884         GError *error = NULL;
885         GdkPixbuf *window_icon = NULL;
886         GtkAction *action;
887         ModestConf *conf;
888         gboolean prefer_formatted;
889         gint file_format;
890         ModestPair *account_pair = NULL;
891
892         g_return_val_if_fail (msg, NULL);
893         g_return_val_if_fail (account_name, NULL);
894         
895         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
896
897         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
898         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
899
900         parent_priv->ui_manager = gtk_ui_manager_new();
901         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
902         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
903
904         /* Add common actions */
905         gtk_action_group_add_actions (action_group,
906                                       modest_msg_edit_action_entries,
907                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
908                                       obj);
909         gtk_action_group_add_toggle_actions (action_group,
910                                              modest_msg_edit_toggle_action_entries,
911                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
912                                              obj);
913         gtk_action_group_add_radio_actions (action_group,
914                                             modest_msg_edit_alignment_radio_action_entries,
915                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
916                                             GTK_JUSTIFY_LEFT,
917                                             G_CALLBACK (modest_ui_actions_on_change_justify),
918                                             obj);
919         gtk_action_group_add_radio_actions (action_group,
920                                             modest_msg_edit_zoom_action_entries,
921                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
922                                             100,
923                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
924                                             obj);
925         gtk_action_group_add_radio_actions (action_group,
926                                             modest_msg_edit_priority_action_entries,
927                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
928                                             0,
929                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
930                                             obj);
931         gtk_action_group_add_radio_actions (action_group,
932                                             modest_msg_edit_file_format_action_entries,
933                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
934                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
935                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
936                                             obj);
937         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
938         g_object_unref (action_group);
939
940         /* Load the UI definition */
941         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
942                                          &error);
943         if (error != NULL) {
944                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
945                 g_clear_error (&error);
946         }
947
948         /* Add accelerators */
949         gtk_window_add_accel_group (GTK_WINDOW (obj), 
950                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
951
952         /* Menubar */
953         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
954         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
955
956         /* Init window */
957         init_window (MODEST_MSG_EDIT_WINDOW(obj));
958
959         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
960                 
961         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
962
963         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
964
965         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
966
967         account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
968         if (account_pair != NULL)
969                 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
970
971         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
972
973         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
974
975         /* Set window icon */
976         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
977         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
978
979         /* Dim at start clipboard actions */
980         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
981         gtk_action_set_sensitive (action, FALSE);
982         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
983         gtk_action_set_sensitive (action, FALSE);
984         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
985         gtk_action_set_sensitive (action, FALSE);
986
987         /* Update select all */
988         update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
989         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
990         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
991         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
992         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
993
994         /* set initial state of cc and bcc */
995         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
996         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
997                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
998         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
999         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1000                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1001
1002         /* Setup the file format */
1003         conf = modest_runtime_get_conf ();
1004         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1005         if (error) {
1006                 g_clear_error (&error);
1007                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1008         } else
1009                 file_format = (prefer_formatted) ? 
1010                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
1011                         MODEST_FILE_FORMAT_PLAIN_TEXT;
1012         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1013
1014         update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1015         
1016         return (ModestWindow*) obj;
1017 }
1018
1019 static gint
1020 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1021 {
1022         GString **string_buffer = (GString **) user_data;
1023
1024         *string_buffer = g_string_append (*string_buffer, buffer);
1025    
1026         return 0;
1027 }
1028
1029 /**
1030  * @result: A new string which should be freed with g_free().
1031  */
1032 static gchar *
1033 get_formatted_data (ModestMsgEditWindow *edit_window)
1034 {
1035         ModestMsgEditWindowPrivate *priv;
1036         GString *string_buffer = g_string_new ("");
1037         
1038         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1039
1040         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1041
1042         return g_string_free (string_buffer, FALSE);
1043                                                                         
1044 }
1045
1046 MsgData * 
1047 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1048 {
1049         MsgData *data;
1050         const gchar *account_name;
1051         ModestMsgEditWindowPrivate *priv;
1052         
1053         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1054
1055         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1056                                                                         
1057         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1058         g_return_val_if_fail (account_name, NULL);
1059         
1060         
1061         /* don't free these (except from) */
1062         data = g_slice_new0 (MsgData);
1063         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1064                                                              account_name);
1065         data->account_name = g_strdup (account_name);
1066         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1067         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1068         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1069         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1070         if (priv->draft_msg) {
1071                 data->draft_msg = g_object_ref (priv->draft_msg);
1072         } else {
1073                 data->draft_msg = NULL;
1074         }
1075
1076         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1077         GtkTextIter b, e;
1078         gtk_text_buffer_get_bounds (buf, &b, &e);
1079         data->plain_body = g_strdup (gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE)); /* returns a copy */
1080
1081         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1082                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1083         else
1084                 data->html_body = NULL;
1085
1086         /* deep-copy the data */
1087         GList *cursor = priv->attachments;
1088         data->attachments = NULL;
1089         while (cursor) {
1090                 if (!(TNY_IS_MIME_PART(cursor->data))) {
1091                         g_warning ("strange data in attachment list");
1092                         continue;
1093                 }
1094                 data->attachments = g_list_append (data->attachments,
1095                                                    g_object_ref (cursor->data));
1096                 cursor = g_list_next (cursor);
1097         }
1098         
1099         data->priority_flags = priv->priority_flags;
1100
1101         return data;
1102 }
1103
1104
1105 static void
1106 unref_gobject (GObject *obj, gpointer data)
1107 {
1108         if (!G_IS_OBJECT(obj))
1109                 return;
1110         g_object_unref (obj);
1111 }
1112
1113 void 
1114 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1115                                                       MsgData *data)
1116 {
1117         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1118
1119         if (!data)
1120                 return;
1121
1122         g_free (data->to);
1123         g_free (data->cc);
1124         g_free (data->bcc);
1125         g_free (data->subject);
1126         g_free (data->plain_body);
1127         g_free (data->html_body);
1128         g_free (data->account_name);
1129         
1130         if (data->draft_msg != NULL) {
1131                 g_object_unref (data->draft_msg);
1132                 data->draft_msg = NULL;
1133         }
1134         
1135         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1136         g_list_free (data->attachments);
1137         
1138         g_slice_free (MsgData, data);
1139 }
1140
1141 ModestMsgEditFormat
1142 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1143 {
1144         gboolean rich_text;
1145         ModestMsgEditWindowPrivate *priv = NULL;
1146         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1147
1148         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1149
1150         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1151         if (rich_text)
1152                 return MODEST_MSG_EDIT_FORMAT_HTML;
1153         else
1154                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1155 }
1156
1157 void
1158 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1159                                    ModestMsgEditFormat format)
1160 {
1161         ModestMsgEditWindowPrivate *priv;
1162
1163         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1164         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1165
1166         switch (format) {
1167         case MODEST_MSG_EDIT_FORMAT_HTML:
1168                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1169                 break;
1170         case MODEST_MSG_EDIT_FORMAT_TEXT:
1171                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1172                 break;
1173         default:
1174                 g_return_if_reached ();
1175         }
1176 }
1177
1178 ModestMsgEditFormatState *
1179 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1180 {
1181         ModestMsgEditFormatState *format_state = NULL;
1182         ModestMsgEditWindowPrivate *priv;
1183         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1184
1185         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1186         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1187
1188         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1189
1190         format_state = g_new0 (ModestMsgEditFormatState, 1);
1191         format_state->bold = buffer_format->bold&0x1;
1192         format_state->italics = buffer_format->italic&0x1;
1193         format_state->bullet = buffer_format->bullet&0x1;
1194         format_state->color = buffer_format->color;
1195         format_state->font_size = buffer_format->font_size;
1196         format_state->font_family = wp_get_font_name (buffer_format->font);
1197         format_state->justification = buffer_format->justification;
1198         g_free (buffer_format);
1199
1200         return format_state;
1201  
1202 }
1203
1204 void
1205 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1206                                          const ModestMsgEditFormatState *format_state)
1207 {
1208         ModestMsgEditWindowPrivate *priv;
1209         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1210         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1211         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1212         g_return_if_fail (format_state != NULL);
1213
1214         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1215         gtk_widget_grab_focus (priv->msg_body);
1216         buffer_format->bold = (format_state->bold != FALSE);
1217         buffer_format->italic = (format_state->italics != FALSE);
1218         buffer_format->color = format_state->color;
1219         buffer_format->font_size = format_state->font_size;
1220         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1221         buffer_format->justification = format_state->justification;
1222         buffer_format->bullet = format_state->bullet;
1223
1224         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1225
1226         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1227         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1228         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
1229         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1230         buffer_format->cs.font = (buffer_format->font != current_format->font);
1231         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1232         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1233
1234         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1235         if (buffer_format->cs.bold) {
1236                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1237         }
1238         if (buffer_format->cs.italic) {
1239                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1240         }
1241         if (buffer_format->cs.color) {
1242                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1243         }
1244         if (buffer_format->cs.font_size) {
1245                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1246         }
1247         if (buffer_format->cs.justification) {
1248                 switch (buffer_format->justification) {
1249                 case GTK_JUSTIFY_LEFT:
1250                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1251                         break;
1252                 case GTK_JUSTIFY_CENTER:
1253                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1254                         break;
1255                 case GTK_JUSTIFY_RIGHT:
1256                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1257                         break;
1258                 default:
1259                         break;
1260                 }
1261                         
1262         }
1263         if (buffer_format->cs.font) {
1264                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1265         }
1266         if (buffer_format->cs.bullet) {
1267                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((int)buffer_format->bullet));
1268         }
1269 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1270         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1271
1272         g_free (current_format);
1273
1274 }
1275
1276 static void
1277 toggle_action_set_active_block_notify (GtkToggleAction *action,
1278                                        gboolean value)
1279 {
1280         GSList *proxies = NULL;
1281
1282         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1283              proxies != NULL; proxies = g_slist_next (proxies)) {
1284                 GtkWidget *widget = (GtkWidget *) proxies->data;
1285                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
1286         }
1287
1288         gtk_toggle_action_set_active (action, value);
1289
1290         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1291              proxies != NULL; proxies = g_slist_next (proxies)) {
1292                 GtkWidget *widget = (GtkWidget *) proxies->data;
1293                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
1294         }
1295 }
1296
1297 static void
1298 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1299 {
1300         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1301         GtkAction *action;
1302         ModestWindowPrivate *parent_priv;
1303         ModestMsgEditWindowPrivate *priv;
1304         GtkWidget *new_size_menuitem;
1305         GtkWidget *new_font_menuitem;
1306         
1307         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1308         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1309
1310         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1311                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1312                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1313                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1314         } else {
1315                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1316                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1317                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1318         }
1319
1320         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1321         
1322         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1323         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1324
1325         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1326         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1327
1328         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1329         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1330
1331         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1332                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1333                                          window);
1334         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1335         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1336                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1337                                            window);
1338
1339         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1340                                                       buffer_format->font_size))->data);
1341         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1342                 GtkWidget *label;
1343                 gchar *markup;
1344
1345                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1346                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1347                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1348                 g_free (markup);
1349                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1350                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1351                                                  window);
1352                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1353                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1354                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1355                                                    window);
1356         }
1357
1358         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1359                                                       buffer_format->font))->data);
1360         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1361                 GtkWidget *label;
1362                 gchar *markup;
1363
1364                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1365                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1366                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1367                 g_free (markup);
1368                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1369                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1370                                                  window);
1371                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1372                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1373                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1374                                                    window);
1375         }
1376
1377         g_free (buffer_format);
1378
1379 }
1380
1381
1382 void
1383 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1384 {
1385         
1386         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1387         ModestMsgEditWindowPrivate *priv;
1388         GtkWidget *dialog = NULL;
1389         gint response;
1390         const GdkColor *new_color = NULL;
1391         
1392         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1393         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1394         
1395 #ifdef MODEST_HILDON_VERSION_0  
1396         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1397         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1398 #else
1399         dialog = hildon_color_chooser_new ();
1400         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1401 #endif /*MODEST_HILDON_VERSION_0*/              
1402         g_free (buffer_format);
1403
1404         response = gtk_dialog_run (GTK_DIALOG (dialog));
1405         switch (response) {
1406         case GTK_RESPONSE_OK: {
1407 #ifdef MODEST_HILDON_VERSION_0
1408                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1409 #else
1410                 GdkColor col;
1411                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1412                 new_color = &col;
1413 #endif /*MODEST_HILDON_VERSION_0*/
1414         }
1415
1416         break;
1417         default:
1418                 break;
1419         }
1420         gtk_widget_destroy (dialog);
1421
1422         if (new_color != NULL)
1423                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1424
1425 }
1426
1427 void
1428 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1429 {
1430         
1431         ModestMsgEditWindowPrivate *priv;
1432         GtkWidget *dialog = NULL;
1433         gint response;
1434         GdkColor *old_color = NULL;
1435         const GdkColor *new_color = NULL;
1436         
1437         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1438         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1439         
1440 #ifdef MODEST_HILDON_VERSION_0  
1441         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1442         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1443 #else
1444         dialog = hildon_color_chooser_new ();
1445         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1446 #endif /*MODEST_HILDON_VERSION_9*/              
1447
1448         response = gtk_dialog_run (GTK_DIALOG (dialog));
1449         switch (response) {
1450         case GTK_RESPONSE_OK: {
1451 #ifdef MODEST_HILDON_VERSION_0
1452                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1453 #else
1454                 GdkColor col;
1455                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1456                 new_color = &col;
1457 #endif /*MODEST_HILDON_VERSION_0*/
1458           }
1459                 break;
1460         default:
1461                 break;
1462         }
1463         gtk_widget_destroy (dialog);
1464
1465         if (new_color != NULL)
1466                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1467
1468 }
1469
1470
1471 void
1472 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1473 {
1474         
1475         ModestMsgEditWindowPrivate *priv;
1476         GtkWidget *dialog = NULL;
1477         gint response = 0;
1478         GSList *uris = NULL;
1479         GSList *uri_node = NULL;
1480         
1481         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1482         
1483         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1484         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1485         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1486
1487         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1488
1489         response = gtk_dialog_run (GTK_DIALOG (dialog));
1490         switch (response) {
1491         case GTK_RESPONSE_OK:
1492                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1493                 break;
1494         default:
1495                 break;
1496         }
1497         gtk_widget_destroy (dialog);
1498
1499         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1500                 const gchar *uri;
1501                 GnomeVFSHandle *handle = NULL;
1502                 GnomeVFSResult result;
1503                 GtkTextIter position;
1504                 GtkTextMark *insert_mark;
1505
1506                 uri = (const gchar *) uri_node->data;
1507                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1508                 if (result == GNOME_VFS_OK) {
1509                         GdkPixbufLoader *loader;
1510                         GdkPixbuf *pixbuf;
1511                         GnomeVFSFileInfo info;
1512                         gchar *filename, *basename;
1513                         TnyMimePart *mime_part;
1514                         TnyStream *stream;
1515                         gchar *content_id;
1516                         const gchar *mime_type = NULL;
1517
1518                         filename = g_filename_from_uri (uri, NULL, NULL);
1519                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) 
1520                             == GNOME_VFS_OK)
1521                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1522
1523                         mime_part = tny_platform_factory_new_mime_part
1524                                 (modest_runtime_get_platform_factory ());
1525                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1526                         
1527                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1528                         
1529                         content_id = g_strdup_printf ("%d", priv->last_cid);
1530                         tny_mime_part_set_content_id (mime_part, content_id);
1531                         g_free (content_id);
1532                         priv->last_cid++;
1533                         
1534                         basename = g_path_get_basename (filename);
1535                         tny_mime_part_set_filename (mime_part, basename);
1536                         g_free (basename);
1537                         
1538                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1539                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1540                                                                 mime_part);
1541                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1542                         gtk_widget_show_all (priv->attachments_caption);
1543                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1544                         g_free (filename);
1545
1546                         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1547                         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1548                                 unsigned char read_buffer[128];
1549                                 gint readed;
1550                                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1551                                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
1552                                         break;
1553                         }
1554                         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1555                         g_object_ref (pixbuf);
1556                         gdk_pixbuf_loader_close (loader, NULL);
1557                         g_object_unref (loader);
1558
1559                         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1560                                 GdkPixbuf *new_pixbuf;
1561                                 gint new_height;
1562                                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1563                                         gdk_pixbuf_get_width (pixbuf);
1564                                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1565                                 g_object_unref (pixbuf);
1566                                 pixbuf = new_pixbuf;
1567                         }
1568
1569                         if (pixbuf != NULL) {
1570                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1571                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1572                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1573                         } 
1574                 }
1575         }
1576
1577
1578 }
1579
1580 void
1581 modest_msg_edit_window_attach_file (ModestMsgEditWindow *window)
1582 {
1583         
1584         ModestMsgEditWindowPrivate *priv;
1585         GtkWidget *dialog = NULL;
1586         gint response = 0;
1587         GSList *uris = NULL;
1588         GSList *uri_node;
1589         
1590         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1591         
1592         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1593         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1594
1595         response = gtk_dialog_run (GTK_DIALOG (dialog));
1596         switch (response) {
1597         case GTK_RESPONSE_OK:
1598                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1599                 break;
1600         default:
1601                 break;
1602         }
1603         gtk_widget_destroy (dialog);
1604
1605         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1606                 const gchar *uri;
1607                 GnomeVFSHandle *handle = NULL;
1608                 GnomeVFSResult result;
1609
1610                 uri = (const gchar *) uri_node->data;
1611                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1612                 if (result == GNOME_VFS_OK) {
1613                         TnyMimePart *mime_part;
1614                         TnyStream *stream;
1615                         const gchar *mime_type = NULL;
1616                         gchar *basename;
1617                         gchar *filename;
1618                         gchar *content_id;
1619                         GnomeVFSFileInfo info;
1620
1621                         filename = g_filename_from_uri (uri, NULL, NULL);
1622                         
1623                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
1624                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1625                         mime_part = tny_platform_factory_new_mime_part
1626                                 (modest_runtime_get_platform_factory ());
1627                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1628                         
1629                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1630                         
1631                         content_id = g_strdup_printf ("%d", priv->last_cid);
1632                         tny_mime_part_set_content_id (mime_part, content_id);
1633                         g_free (content_id);
1634                         priv->last_cid++;
1635                         
1636                         basename = g_path_get_basename (filename);
1637                         tny_mime_part_set_filename (mime_part, basename);
1638                         g_free (basename);
1639                         
1640                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1641                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1642                                                                 mime_part);
1643                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1644                         gtk_widget_show_all (priv->attachments_caption);
1645                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1646                         g_free (filename);
1647
1648                 } 
1649         }
1650         g_slist_foreach (uris, (GFunc) g_free, NULL);
1651         g_slist_free (uris);
1652 }
1653
1654 void
1655 modest_msg_edit_window_attach_file_noninteractive (
1656                 ModestMsgEditWindow *window,
1657                 const gchar *file_uri)
1658 {
1659         
1660         ModestMsgEditWindowPrivate *priv;
1661         
1662         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1663
1664         if (file_uri && strlen(file_uri)) {
1665                 gint file_id = 0;
1666                 
1667                 /* TODO: We should probably try to use only the URI,
1668                  * instead of using a filename.
1669                  */
1670                 gchar* filename = g_filename_from_uri (file_uri, NULL, NULL);
1671                 if (!filename) {
1672                         g_warning("%s: g_filename_from_uri('%s') failed.\n", __FUNCTION__, file_uri);
1673                 }
1674
1675                 file_id = g_open (filename, O_RDONLY, 0);
1676                 if (file_id != -1) {
1677                         TnyMimePart *mime_part;
1678                         TnyStream *stream;
1679                         const gchar *mime_type;
1680                         gchar *basename;
1681                         gchar *content_id;
1682 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1683                         mime_type = gnome_vfs_get_mime_type(filename);
1684 #else
1685                         mime_type = gnome_vfs_get_file_mime_type_fast (filename, NULL);
1686 #endif
1687                         mime_part = tny_platform_factory_new_mime_part
1688                                 (modest_runtime_get_platform_factory ());
1689                         stream = TNY_STREAM (tny_fs_stream_new (file_id));
1690                         
1691                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1692                         
1693                         content_id = g_strdup_printf ("%d", priv->last_cid);
1694                         tny_mime_part_set_content_id (mime_part, content_id);
1695                         g_free (content_id);
1696                         priv->last_cid++;
1697                         
1698                         basename = g_path_get_basename (filename);
1699                         tny_mime_part_set_filename (mime_part, basename);
1700                         g_free (basename);
1701                         
1702                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1703                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1704                                                                 mime_part);
1705                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1706                         gtk_widget_show_all (priv->attachments_caption);
1707                 } else if (file_id == -1) {
1708                         close (file_id);
1709                         g_warning("file to be attached does not exist: %s", filename);
1710                 }
1711
1712                 g_free (filename);
1713         }
1714 }
1715
1716 void
1717 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1718                                           GList *att_list)
1719 {
1720         ModestMsgEditWindowPrivate *priv;
1721         gboolean clean_list = FALSE;
1722
1723         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1724         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1725
1726         if (att_list == NULL) {
1727                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1728                 clean_list = TRUE;
1729         }
1730
1731         if (att_list == NULL) {
1732                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1733         } else {
1734                 GtkWidget *confirmation_dialog = NULL;
1735                 gboolean dialog_response;
1736                 GList *node;
1737                 gchar *message = NULL;
1738                 const gchar *filename = NULL;
1739
1740                 if (att_list->next == NULL) {
1741                         filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1742                 } else {
1743                         filename = "";
1744                 }
1745                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1746                                                     att_list->next == NULL), filename);
1747                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1748                 g_free (message);
1749                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1750                 gtk_widget_destroy (confirmation_dialog);
1751                 if (!dialog_response) {
1752                         if (clean_list)
1753                                 g_list_free (att_list);
1754                         return;
1755                 }
1756                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1757
1758                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1759                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1760                         const gchar *att_id;
1761                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1762
1763                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1764                                                                    mime_part);
1765                         if (priv->attachments == NULL)
1766                                 gtk_widget_hide (priv->attachments_caption);
1767                         att_id = tny_mime_part_get_content_id (mime_part);
1768                         if (att_id != NULL)
1769                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1770                                                                  att_id);
1771                         g_object_unref (mime_part);
1772                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1773                 }
1774         }
1775
1776         if (clean_list)
1777                 g_list_free (att_list);
1778 }
1779
1780 static void
1781 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1782                                             gpointer userdata)
1783 {
1784         ModestMsgEditWindowPrivate *priv;
1785         GdkColor *new_color;
1786         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1787         
1788 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
1789         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1790 #else 
1791         GdkColor col;
1792         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1793         new_color = &col;
1794 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1795
1796         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1797         
1798         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1799
1800 }
1801
1802 static void
1803 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1804                                     gpointer userdata)
1805 {
1806         ModestMsgEditWindowPrivate *priv;
1807         gint new_size_index;
1808         ModestMsgEditWindow *window;
1809         GtkWidget *label;
1810         
1811         window = MODEST_MSG_EDIT_WINDOW (userdata);
1812         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1813         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1814
1815         if (gtk_check_menu_item_get_active (menu_item)) {
1816                 gchar *markup;
1817                 WPTextBufferFormat format;
1818
1819                 memset (&format, 0, sizeof (format));
1820                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1821
1822                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1823                 
1824                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1825                 format.cs.font_size = TRUE;
1826                 format.cs.text_position = TRUE;
1827                 format.cs.font = TRUE;
1828                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1829 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1830
1831                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1832                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
1833                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1834                 
1835                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1836                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1837                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1838                 g_free (markup);
1839         }
1840 }
1841
1842 static void
1843 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1844                                     gpointer userdata)
1845 {
1846         ModestMsgEditWindowPrivate *priv;
1847         gint new_font_index;
1848         ModestMsgEditWindow *window;
1849         GtkWidget *label;
1850         
1851         window = MODEST_MSG_EDIT_WINDOW (userdata);
1852         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1853         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1854
1855         if (gtk_check_menu_item_get_active (menu_item)) {
1856                 gchar *markup;
1857
1858                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1859                 
1860                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1861
1862                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1863                                                    (gpointer) new_font_index))
1864                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1865                 
1866                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1867                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1868                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1869                 g_free (markup);
1870         }
1871 }
1872
1873 static void
1874 modest_msg_edit_window_set_zoom (ModestWindow *window,
1875                                  gdouble zoom)
1876 {
1877         ModestMsgEditWindowPrivate *priv;
1878         ModestWindowPrivate *parent_priv;
1879         GtkRadioAction *zoom_radio_action;
1880      
1881         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1882
1883         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1884         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1885         priv->zoom_level = zoom;
1886         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
1887
1888         /* Zoom level menu options should be updated with the current zoom level */
1889         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1890         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1891                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1892 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1893         /* FIXME: Not availible before Gtk 2.10 */
1894 #else
1895         gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
1896 #endif
1897 }
1898
1899 static gdouble
1900 modest_msg_edit_window_get_zoom (ModestWindow *window)
1901 {
1902         ModestMsgEditWindowPrivate *priv;
1903      
1904         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1905
1906         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1907         return priv->zoom_level;
1908 }
1909
1910 static gboolean
1911 zoom_allowed (ModestMsgEditWindow *window)
1912 {
1913         GtkWidget *focus;
1914
1915         focus = gtk_window_get_focus (GTK_WINDOW (window));
1916         return (focus != NULL && WP_IS_TEXT_VIEW (focus));
1917 }
1918
1919 static gboolean
1920 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1921 {
1922         ModestWindowPrivate *parent_priv;
1923         GtkRadioAction *zoom_radio_action;
1924         GSList *group, *node;
1925
1926         /* First we check if the text view is focused. If not, zooming is not allowed */
1927         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
1928                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
1929                 return FALSE;
1930         }
1931
1932         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1933         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1934                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1935
1936         group = gtk_radio_action_get_group (zoom_radio_action);
1937
1938         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1939                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1940                 return FALSE;
1941         }
1942
1943         for (node = group; node != NULL; node = g_slist_next (node)) {
1944                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1945                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1946                         return TRUE;
1947                 }
1948         }
1949         return FALSE;
1950 }
1951
1952 static gboolean
1953 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1954 {
1955         ModestWindowPrivate *parent_priv;
1956         GtkRadioAction *zoom_radio_action;
1957         GSList *group, *node;
1958
1959         /* First we check if the text view is focused. If not, zooming is not allowed */
1960         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
1961                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
1962                 return FALSE;
1963         }
1964
1965         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1966         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1967                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1968
1969         group = gtk_radio_action_get_group (zoom_radio_action);
1970
1971         for (node = group; node != NULL; node = g_slist_next (node)) {
1972                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1973                         if (node->next != NULL) {
1974                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1975                                 return TRUE;
1976                         } else
1977                                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1978                         break;
1979                 }
1980         }
1981         return FALSE;
1982 }
1983
1984 static gboolean
1985 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1986 {
1987         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1988                 ModestWindowPrivate *parent_priv;
1989                 ModestWindowMgr *mgr;
1990                 gboolean is_fullscreen;
1991                 GtkAction *fs_toggle_action;
1992                 gboolean active;
1993
1994                 mgr = modest_runtime_get_window_mgr ();
1995                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1996
1997                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1998                 
1999                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2000                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2001                 if (is_fullscreen != active)
2002                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2003         }
2004
2005         return FALSE;
2006
2007 }
2008
2009 void
2010 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2011 {
2012         ModestWindowPrivate *parent_priv;
2013         GtkAction *fs_toggle_action;
2014         gboolean active;
2015
2016         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2017
2018         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2019         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2020         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2021 }
2022
2023 void
2024 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2025                                 gboolean show)
2026 {
2027         ModestMsgEditWindowPrivate *priv = NULL;
2028         const gchar *recipients;
2029         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2030
2031         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2032         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2033         recipients = modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field));
2034         if ((show) || ((recipients != NULL) && (recipients[0] != '\0')))
2035                 gtk_widget_show (priv->cc_caption);
2036         else
2037                 gtk_widget_hide (priv->cc_caption);
2038         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2039 }
2040
2041 void
2042 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2043                                  gboolean show)
2044 {
2045         ModestMsgEditWindowPrivate *priv = NULL;
2046         const gchar *recipients;
2047         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2048
2049         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2050         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2051         recipients = modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field));
2052         if ((show) || ((recipients != NULL) && (recipients[0] != '\0')))
2053                 gtk_widget_show (priv->bcc_caption);
2054         else
2055                 gtk_widget_hide (priv->bcc_caption);
2056         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2057 }
2058
2059 static void
2060 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2061                                          ModestRecptEditor *editor)
2062 {
2063         ModestMsgEditWindowPrivate *priv;
2064
2065         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2066         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2067         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2068
2069         if (editor == NULL) {
2070                 GtkWidget *view_focus;
2071                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2072
2073                 /* This code should be kept in sync with ModestRecptEditor. The
2074                    textview inside the recpt editor is the one that really gets the
2075                    focus. As it's inside a scrolled window, and this one inside the
2076                    hbox recpt editor inherits from, we'll need to go up in the 
2077                    hierarchy to know if the text view is part of the recpt editor
2078                    or if it's a different text entry */
2079
2080                 if (gtk_widget_get_parent (view_focus)) {
2081                         GtkWidget *first_parent;
2082
2083                         first_parent = gtk_widget_get_parent (view_focus);
2084                         if (gtk_widget_get_parent (first_parent) && 
2085                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2086                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2087                         }
2088                 }
2089
2090                 if (editor == NULL)
2091                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2092
2093         }
2094
2095         modest_address_book_select_addresses (editor);
2096
2097 }
2098
2099 void
2100 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2101 {
2102         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2103
2104         modest_msg_edit_window_open_addressbook (window, NULL);
2105 }
2106
2107 static void
2108 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2109                                      gboolean show_toolbar)
2110 {
2111         ModestWindowPrivate *parent_priv;
2112         
2113         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2114         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2115
2116         /* FIXME: we can not just use the code of
2117            modest_msg_edit_window_setup_toolbar because it has a
2118            mixture of both initialization and creation code. */
2119
2120         if (show_toolbar)
2121                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2122         else
2123                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2124 }
2125
2126 void
2127 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2128                                            TnyHeaderFlags priority_flags)
2129 {
2130         ModestMsgEditWindowPrivate *priv;
2131         ModestWindowPrivate *parent_priv;
2132
2133         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2134
2135         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2136         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2137         priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2138
2139         if (priv->priority_flags != priority_flags) {
2140                 GtkAction *priority_action = NULL;
2141
2142                 priv->priority_flags = priority_flags;
2143
2144                 switch (priority_flags) {
2145                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2146                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2147                         gtk_widget_show (priv->priority_icon);
2148                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2149                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2150                         break;
2151                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2152                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2153                         gtk_widget_show (priv->priority_icon);
2154                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2155                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2156                         break;
2157                 default:
2158                         gtk_widget_hide (priv->priority_icon);
2159                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2160                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2161                         break;
2162                 }
2163                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2164                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2165         }
2166 }
2167
2168 void
2169 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2170                                         gint file_format)
2171 {
2172         ModestMsgEditWindowPrivate *priv;
2173         ModestWindowPrivate *parent_priv;
2174         gint current_format;
2175
2176         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2177
2178         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2179         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2180
2181         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2182                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2183
2184         if (current_format != file_format) {
2185                 switch (file_format) {
2186                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2187                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2188                         break;
2189                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2190                 {
2191                         GtkWidget *dialog;
2192                         gint response;
2193                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2194                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2195                         gtk_widget_destroy (dialog);
2196                         if (response == GTK_RESPONSE_OK) {
2197                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2198                         } else {
2199                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2200                                 toggle_action_set_active_block_notify (action, TRUE);
2201                         }
2202                 }
2203                         break;
2204                 }
2205                 update_dimmed (window);
2206         }
2207 }
2208
2209 void
2210 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2211 {
2212         GtkWidget *dialog;
2213         ModestMsgEditWindowPrivate *priv;
2214         WPTextBufferFormat oldfmt, fmt;
2215         gint old_position = 0;
2216         gint response = 0;
2217         gint position = 0;
2218         gint font_size;
2219         GdkColor *color = NULL;
2220         gboolean bold, bold_set, italic, italic_set;
2221         gboolean underline, underline_set;
2222         gboolean strikethrough, strikethrough_set;
2223         gboolean position_set;
2224         gboolean font_size_set, font_set, color_set;
2225         gchar *font_name;
2226
2227         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2228         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2229         
2230         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2231
2232         /* First we get the currently selected font information */
2233         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2234         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2235
2236         switch (oldfmt.text_position) {
2237         case TEXT_POSITION_NORMAL:
2238                 old_position = 0;
2239                 break;
2240         case TEXT_POSITION_SUPERSCRIPT:
2241                 old_position = 1;
2242                 break;
2243         default:
2244                 old_position = -1;
2245                 break;
2246         }
2247
2248         g_object_set (G_OBJECT (dialog),
2249                       "bold", oldfmt.bold != FALSE,
2250                       "bold-set", !oldfmt.cs.bold,
2251                       "underline", oldfmt.underline != FALSE,
2252                       "underline-set", !oldfmt.cs.underline,
2253                       "italic", oldfmt.italic != FALSE,
2254                       "italic-set", !oldfmt.cs.italic,
2255                       "strikethrough", oldfmt.strikethrough != FALSE,
2256                       "strikethrough-set", !oldfmt.cs.strikethrough,
2257                       "color", &oldfmt.color,
2258                       "color-set", !oldfmt.cs.color,
2259                       "size", wp_font_size[oldfmt.font_size],
2260                       "size-set", !oldfmt.cs.font_size,
2261                       "position", old_position,
2262                       "position-set", !oldfmt.cs.text_position,
2263                       "family", wp_get_font_name (oldfmt.font),
2264                       "family-set", !oldfmt.cs.font,
2265                       NULL);
2266
2267         gtk_widget_show_all (dialog);
2268         response = gtk_dialog_run (GTK_DIALOG (dialog));
2269         if (response == GTK_RESPONSE_OK) {
2270
2271                 g_object_get( dialog,
2272                               "bold", &bold,
2273                               "bold-set", &bold_set,
2274                               "underline", &underline,
2275                               "underline-set", &underline_set,
2276                               "italic", &italic,
2277                               "italic-set", &italic_set,
2278                               "strikethrough", &strikethrough,
2279                               "strikethrough-set", &strikethrough_set,
2280                               "color", &color,
2281                               "color-set", &color_set,
2282                               "size", &font_size,
2283                               "size-set", &font_size_set,
2284                               "family", &font_name,
2285                               "family-set", &font_set,
2286                               "position", &position,
2287                               "position-set", &position_set,
2288                               NULL );
2289                 
2290         }       
2291
2292         if (response == GTK_RESPONSE_OK) {
2293                 memset(&fmt, 0, sizeof(fmt));
2294                 if (bold_set) {
2295                         fmt.bold = bold;
2296                         fmt.cs.bold = TRUE;
2297                 }
2298                 if (italic_set) {
2299                         fmt.italic = italic;
2300                         fmt.cs.italic = TRUE;
2301                 }
2302                 if (underline_set) {
2303                         fmt.underline = underline;
2304                         fmt.cs.underline = TRUE;
2305                 }
2306                 if (strikethrough_set) {
2307                         fmt.strikethrough = strikethrough;
2308                         fmt.cs.strikethrough = TRUE;
2309                 }
2310                 if (position_set) {
2311                         fmt.text_position =
2312                                 ( position == 0 )
2313                                 ? TEXT_POSITION_NORMAL
2314                                 : ( ( position == 1 )
2315                                     ? TEXT_POSITION_SUPERSCRIPT
2316                                     : TEXT_POSITION_SUBSCRIPT );
2317                         fmt.cs.text_position = TRUE;
2318                 }
2319                 if (color_set) {
2320                         fmt.color = *color;
2321                         fmt.cs.color = TRUE;
2322                 }
2323                 if (font_set) {
2324                         fmt.font = wp_get_font_index(font_name,
2325                                                      DEFAULT_FONT);
2326                         fmt.cs.font = TRUE;
2327                 }
2328                 g_free(font_name);
2329                 if (font_size_set) {
2330                         fmt.font_size = wp_get_font_size_index(
2331                                 font_size, DEFAULT_FONT_SIZE);
2332                         fmt.cs.font_size = TRUE;
2333                 }
2334                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2335         }
2336         gtk_widget_destroy (dialog);
2337         
2338         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2339 }
2340
2341 void
2342 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2343 {
2344         ModestMsgEditWindowPrivate *priv;
2345
2346         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2347         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2348         
2349         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2350
2351         update_dimmed (window);
2352
2353 }
2354
2355 void
2356 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2357 {
2358         ModestMsgEditWindowPrivate *priv;
2359
2360         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2361         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2362         
2363         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2364
2365         update_dimmed (window);
2366
2367 }
2368
2369 static void
2370 update_dimmed (ModestMsgEditWindow *window)
2371 {
2372         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2373         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2374         GtkAction *action;
2375         GtkWidget *widget;
2376         gboolean rich_text;
2377         gboolean editor_focused;
2378
2379         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2380         editor_focused = gtk_widget_is_focus (priv->msg_body);
2381
2382         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2383         gtk_action_set_sensitive (action, rich_text && editor_focused);
2384         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2385         gtk_action_set_sensitive (action, rich_text && editor_focused);
2386         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2387         gtk_action_set_sensitive (action, rich_text && editor_focused);
2388         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2389         gtk_action_set_sensitive (action, rich_text && editor_focused);
2390         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2391         gtk_action_set_sensitive (action, rich_text && editor_focused);
2392         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2393         gtk_action_set_sensitive (action, rich_text && editor_focused);
2394         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2395         gtk_action_set_sensitive (action, rich_text && editor_focused);
2396         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2397         gtk_action_set_sensitive (action, rich_text && editor_focused);
2398         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2399         gtk_action_set_sensitive (action, rich_text && editor_focused);
2400         widget = priv->font_color_button;
2401         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2402         widget = priv->font_size_toolitem;
2403         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2404         widget = priv->font_face_toolitem;
2405         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2406 }
2407
2408 static void
2409 setup_insensitive_handlers (ModestMsgEditWindow *window)
2410 {
2411         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2412         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2413         GtkWidget *widget;
2414
2415         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2416         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2417         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2418         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2419         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2420         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2421         widget = priv->font_color_button;
2422         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2423         widget = priv->font_size_toolitem;
2424         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2425         widget = priv->font_face_toolitem;
2426         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2427
2428 }
2429
2430 static void  
2431 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2432 {
2433         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2434         GtkAction *action;
2435
2436         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2437         gtk_action_set_sensitive (action, can_undo);
2438 }
2439
2440 static void  
2441 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2442 {
2443         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2444         GtkAction *action;
2445
2446         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2447         gtk_action_set_sensitive (action, can_redo);
2448 }
2449
2450 static void
2451 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2452 {
2453         GtkTextIter iter;
2454         GtkTextIter match_start, match_end;
2455
2456         if (image_id == NULL)
2457                 return;
2458
2459         gtk_text_buffer_get_start_iter (buffer, &iter);
2460
2461         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2462                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2463                 GSList *node;
2464                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2465                         GtkTextTag *tag = (GtkTextTag *) node->data;
2466                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2467                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2468                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2469                                         gint offset;
2470                                         offset = gtk_text_iter_get_offset (&match_start);
2471                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2472                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2473                                 }
2474                         }
2475                 }
2476                 gtk_text_iter_forward_char (&iter);
2477         }
2478 }
2479
2480 static void
2481 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2482 {
2483         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2484         GtkTextIter real_start, real_end;
2485         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2486
2487         if (gtk_text_iter_compare (start, end) > 0) {
2488                 real_start = *end;
2489                 real_end = *start;
2490         } else {
2491                 real_start = *start;
2492                 real_end = *end;
2493         }
2494         do {
2495                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2496                 GSList *node;
2497                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2498                         GtkTextTag *tag = (GtkTextTag *) node->data;
2499                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2500                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2501
2502                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2503                                                                                  image_id);
2504                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2505                         }
2506                 }
2507         } while (gtk_text_iter_forward_char (&real_start)&&
2508                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2509 }
2510
2511 static gboolean
2512 msg_body_focus (GtkWidget *focus,
2513                 GdkEventFocus *event,
2514                 gpointer userdata)
2515 {
2516         
2517         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2518         return FALSE;
2519 }
2520
2521 static void
2522 recpt_field_changed (GtkTextBuffer *buffer,
2523                   ModestMsgEditWindow *editor)
2524 {
2525         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2526         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2527         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2528         gboolean dim = FALSE;
2529         GtkAction *action;
2530
2531         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2532         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2533         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2534         
2535         dim = ((gtk_text_buffer_get_char_count (to_buffer) + 
2536                 gtk_text_buffer_get_char_count (cc_buffer) +
2537                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2538                         
2539         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2540         gtk_action_set_sensitive (action, !dim);
2541         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2542         gtk_action_set_sensitive (action, !dim);
2543 }
2544
2545 static void  
2546 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2547 {
2548         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2549 }
2550
2551 static void
2552 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2553 {
2554         gboolean rich_text, editor_focused;
2555
2556         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2557         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2558         editor_focused = gtk_widget_is_focus (priv->msg_body);
2559
2560         if (!rich_text)
2561                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2562         else if (!editor_focused)
2563                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2564 }
2565
2566 static void
2567 reset_modified (ModestMsgEditWindow *editor)
2568 {
2569         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2570         GtkTextBuffer *buffer;
2571
2572         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2573         gtk_text_buffer_set_modified (buffer, FALSE);
2574         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2575         gtk_text_buffer_set_modified (buffer, FALSE);
2576         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2577         gtk_text_buffer_set_modified (buffer, FALSE);
2578         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2579 }
2580
2581 gboolean
2582 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2583 {
2584         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2585         GtkTextBuffer *buffer;
2586
2587         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2588         if (gtk_text_buffer_get_modified (buffer))
2589                 return TRUE;
2590         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2591         if (gtk_text_buffer_get_modified (buffer))
2592                 return TRUE;
2593         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2594         if (gtk_text_buffer_get_modified (buffer))
2595                 return TRUE;
2596         if (gtk_text_buffer_get_modified (priv->text_buffer))
2597                 return TRUE;
2598
2599         return FALSE;
2600 }
2601
2602 gboolean
2603 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2604 {
2605         ModestMsgEditWindowPrivate *priv = NULL;
2606
2607         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2608         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2609
2610         /* check if there's no recipient added */
2611         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2612             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2613             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2614                 /* no recipient contents, then select contacts */
2615                 modest_msg_edit_window_open_addressbook (window, NULL);
2616                 return FALSE;
2617         }
2618
2619         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2620                 return FALSE;
2621         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2622                 return FALSE;
2623         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2624                 return FALSE;
2625
2626         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2627
2628         return TRUE;
2629
2630 }
2631
2632 static void
2633 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2634                                                ModestMsgEditWindow *window)
2635 {
2636         modest_msg_edit_window_attach_file (window);
2637 }
2638
2639 static void
2640 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2641                                                GdkEvent *event,
2642                                                ModestMsgEditWindow *window)
2643 {
2644         ModestWindowPrivate *parent_priv;
2645         ModestMsgEditWindowPrivate *priv;
2646         GtkAction *action;
2647         gboolean has_selection;
2648         GtkWidget *focused;
2649         GList *selected_attachments = NULL;
2650         gint n_att_selected = 0;
2651
2652         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2653         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2654         has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
2655         focused = gtk_window_get_focus (GTK_WINDOW (window));
2656
2657         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2658         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2659         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2660         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2661
2662         selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2663         n_att_selected = g_list_length (selected_attachments);
2664         g_list_free (selected_attachments);
2665
2666         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2667         gtk_action_set_sensitive (action, n_att_selected == 1);
2668         
2669         update_paste_dimming (window);
2670 }
2671
2672 static void 
2673 update_window_title (ModestMsgEditWindow *window)
2674 {
2675         ModestMsgEditWindowPrivate *priv = NULL;
2676         const gchar *subject;
2677
2678         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2679         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2680         if (subject == NULL || subject[0] == '\0')
2681                 subject = _("mail_va_new_email");
2682
2683         gtk_window_set_title (GTK_WINDOW (window), subject);
2684
2685 }
2686
2687 static void  
2688 subject_field_changed (GtkEditable *editable, 
2689                        ModestMsgEditWindow *window)
2690 {
2691         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2692         update_window_title (window);
2693         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2694 }
2695
2696 void
2697 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2698                                             gboolean show)
2699 {
2700         ModestMsgEditWindowPrivate *priv = NULL;
2701
2702         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2703         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2704
2705         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2706         if (show) {
2707                 gtk_widget_show_all (priv->find_toolbar);
2708                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2709         } else {
2710                 gtk_widget_hide_all (priv->find_toolbar);
2711                 gtk_widget_grab_focus (priv->msg_body);
2712         }
2713     
2714 }
2715
2716 static gboolean 
2717 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2718                                           const gchar *str,
2719                                           GtkTextIter *match_start,
2720                                           GtkTextIter *match_end)
2721 {
2722         GtkTextIter end_iter;
2723         gchar *str_casefold;
2724         gint str_chars_n;
2725         gchar *range_text;
2726         gchar *range_casefold;
2727         gint offset;
2728         gint range_chars_n;
2729         gboolean result = FALSE;
2730
2731         if (str == NULL)
2732                 return TRUE;
2733         
2734         /* get end iter */
2735         end_iter = *iter;
2736         gtk_text_iter_forward_to_end (&end_iter);
2737
2738         str_casefold = g_utf8_casefold (str, -1);
2739         str_chars_n = strlen (str);
2740
2741         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2742         range_casefold = g_utf8_casefold (range_text, -1);
2743         range_chars_n = strlen (range_casefold);
2744
2745         if (range_chars_n < str_chars_n) {
2746                 g_free (str_casefold);
2747                 g_free (range_text);
2748                 g_free (range_casefold);
2749                 return FALSE;
2750         }
2751
2752         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2753                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2754                 if (!g_utf8_collate (range_subtext, str_casefold)) {
2755                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2756                         result = TRUE;
2757                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2758                                                       match_start, match_end, NULL);
2759                         g_free (found_text);
2760                 }
2761                 g_free (range_subtext);
2762                 if (result)
2763                         break;
2764         }
2765         g_free (str_casefold);
2766         g_free (range_text);
2767         g_free (range_casefold);
2768
2769         return result;
2770 }
2771
2772
2773 static void 
2774 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2775                                             ModestMsgEditWindow *window)
2776 {
2777         gchar *current_search = NULL;
2778         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2779         gboolean result;
2780         GtkTextIter selection_start, selection_end;
2781         GtkTextIter match_start, match_end;
2782         gboolean continue_search = FALSE;
2783
2784         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
2785         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2786                 g_free (current_search);
2787                 g_free (priv->last_search);
2788                 priv->last_search = NULL;
2789                 /* Information banner about empty search */
2790                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2791                 return;
2792         }
2793
2794         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2795                 continue_search = TRUE;
2796         } else {
2797                 g_free (priv->last_search);
2798                 priv->last_search = g_strdup (current_search);
2799         }
2800
2801         if (continue_search) {
2802                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2803                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
2804                                                                    &match_start, &match_end);
2805                 if (!result)
2806                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
2807         } else {
2808                 GtkTextIter buffer_start;
2809                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2810                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
2811                                                                    &match_start, &match_end);
2812                 if (!result)
2813                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
2814         }
2815
2816         /* Mark as selected the string found in search */
2817         if (result) {
2818                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
2819                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
2820         } else {
2821                 g_free (priv->last_search);
2822                 priv->last_search = NULL;
2823         }
2824         g_free (current_search);
2825 }
2826
2827 static void
2828 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
2829                                            ModestMsgEditWindow *window)
2830 {
2831         GtkToggleAction *toggle;
2832         ModestWindowPrivate *parent_priv;
2833         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2834
2835         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
2836         gtk_toggle_action_set_active (toggle, FALSE);
2837 }
2838
2839
2840 static void 
2841 update_paste_dimming (ModestMsgEditWindow *window)
2842 {
2843         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2844         GtkAction *action = NULL;
2845         GtkClipboard *clipboard = NULL;
2846         GtkWidget *focused;
2847         gboolean active;
2848
2849         focused = gtk_window_get_focus (GTK_WINDOW (window));
2850
2851         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2852         active = gtk_clipboard_wait_is_text_available (clipboard);
2853
2854         if (active) {
2855                 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
2856                         active = FALSE;
2857         }
2858
2859         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
2860         gtk_action_set_sensitive (action, active);
2861
2862 }
2863
2864
2865 static void
2866 modest_msg_edit_window_system_clipboard_owner_change (GtkClipboard *clipboard,
2867                                                       GdkEvent *event,
2868                                                       ModestMsgEditWindow *window)
2869 {
2870         update_paste_dimming (window);
2871 }
2872
2873 static void 
2874 update_select_all_dimming (ModestMsgEditWindow *window)
2875 {
2876         GtkWidget *focused;
2877         gboolean dimmed = FALSE;
2878         GtkAction *action;
2879         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2880
2881         focused = gtk_window_get_focus (GTK_WINDOW (window));
2882         if (GTK_IS_ENTRY (focused)) {
2883                 const gchar *current_text;
2884                 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
2885                 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
2886         } else if (GTK_IS_TEXT_VIEW (focused)) {
2887                 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
2888                 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
2889         } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
2890                 dimmed = FALSE;
2891         }
2892         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
2893         gtk_action_set_sensitive (action, !dimmed);
2894 }
2895
2896 static void 
2897 update_zoom_dimming (ModestMsgEditWindow *window)
2898 {
2899         GtkWidget *focused;
2900         gboolean dimmed = FALSE;
2901         GtkAction *action;
2902         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2903
2904         focused = gtk_window_get_focus (GTK_WINDOW (window));
2905         dimmed = ! WP_IS_TEXT_VIEW (focused);
2906         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
2907         gtk_action_set_sensitive (action, !dimmed);
2908 }
2909
2910 static void
2911 edit_menu_activated (GtkAction *action,
2912                      gpointer userdata)
2913 {
2914         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
2915
2916         update_select_all_dimming (window);
2917 }
2918 static void
2919 view_menu_activated (GtkAction *action,
2920                      gpointer userdata)
2921 {
2922         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
2923
2924         update_zoom_dimming (window);
2925 }
2926
2927 gboolean 
2928 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
2929 {
2930         ModestMsgEditWindowPrivate *priv;
2931
2932         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
2933         return priv->sent;
2934 }
2935
2936 void 
2937 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
2938                                  gboolean sent)
2939 {
2940         ModestMsgEditWindowPrivate *priv;
2941
2942         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
2943         priv->sent = sent;
2944 }
2945
2946
2947 void            
2948 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
2949                                   TnyMsg *draft)
2950 {
2951         ModestMsgEditWindowPrivate *priv;
2952         TnyHeader *header = NULL;
2953
2954         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2955         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
2956
2957         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2958         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
2959
2960         if (priv->draft_msg != NULL) {
2961                 header = tny_msg_get_header (priv->draft_msg);
2962                 if (TNY_IS_HEADER (header)) {
2963                         modest_window_mgr_unregister_header (mgr, header);
2964                 }
2965                 g_object_unref (priv->draft_msg);
2966         }
2967
2968         if (draft != NULL) {
2969                 g_object_ref (draft);
2970                 header = tny_msg_get_header (draft);
2971                 if (TNY_IS_HEADER (header))
2972                         modest_window_mgr_register_header (mgr, header);
2973         }
2974
2975         priv->draft_msg = draft;
2976 }