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