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