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