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