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