Added new method to set a new label on captioned
[modest] / src / hildon2 / 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 #include <tny-camel-mem-stream.h>
39
40 #include <config.h>
41
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
44
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
49
50 #include <modest-runtime.h>
51
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <wptextview.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include "modest-msg-edit-window-ui-dimming.h"
68
69 #include "modest-hildon-includes.h"
70 #ifdef MODEST_HAVE_HILDON0_WIDGETS
71 #include <hildon-widgets/hildon-color-chooser.h>
72 #endif
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #ifdef MODEST_HAVE_HILDON0_WIDGETS
75 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #else
77 #include <libgnomevfs/gnome-vfs-mime.h>
78 #endif
79 #include <modest-utils.h>
80 #include "modest-maemo-utils.h"
81 #include <modest-ui-constants.h>
82
83
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 6
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91
92 static gboolean is_wp_text_buffer_started = FALSE;
93
94 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
95 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
96 static void  modest_msg_edit_window_finalize     (GObject *obj);
97
98 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
99 static void  body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
100 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101
102 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
103 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
104 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
105 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
106                                     GtkTextIter *start, GtkTextIter *end,
107                                     gpointer userdata);
108 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
109 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
110 static void  subject_field_insert_text (GtkEditable *editable, 
111                                         gchar *new_text,
112                                         gint new_text_length,
113                                         gint *position,
114                                         ModestMsgEditWindow *window);
115 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116                                                          gpointer userdata);
117 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118                                                  gpointer userdata);
119 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120                                                  gpointer userdata);
121 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124                                                      ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126                                                            ModestMsgEditWindow *window);
127
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
131                                                    gboolean show_toolbar);
132 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133                                                            GdkEvent *event,
134                                                            ModestMsgEditWindow *window);
135 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
136 static void subject_field_move_cursor (GtkEntry *entry,
137                                        GtkMovementStep step,
138                                        gint a1,
139                                        gboolean a2,
140                                        gpointer userdata);
141 static void update_window_title (ModestMsgEditWindow *window);
142
143 /* Find toolbar */
144 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
145                                                         ModestMsgEditWindow *window);
146 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
147                                                        ModestMsgEditWindow *window);
148 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
149                                                           const gchar *str,
150                                                           GtkTextIter *match_start,
151                                                           GtkTextIter *match_end);
152
153 static void remove_tags (WPTextBuffer *buffer);
154
155 static void on_account_removed (TnyAccountStore *account_store, 
156                                 TnyAccount *account,
157                                 gpointer user_data);
158
159 static void init_window (ModestMsgEditWindow *obj);
160
161 gboolean scroll_drag_timeout (gpointer userdata);
162 static void correct_scroll (ModestMsgEditWindow *w);
163 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
164 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
165                                          ModestMsgEditWindow *userdata);
166 static void text_buffer_mark_set (GtkTextBuffer *buffer,
167                                   GtkTextIter *iter,
168                                   GtkTextMark *mark,
169                                   ModestMsgEditWindow *userdata);
170 static void on_message_settings (GtkAction *action,
171                                  ModestMsgEditWindow *window);
172 static void setup_menu (ModestMsgEditWindow *self);
173
174 static void DEBUG_BUFFER (WPTextBuffer *buffer)
175 {
176 #ifdef DEBUG
177         GtkTextIter iter;
178         g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
179
180         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
181         while (!gtk_text_iter_is_end (&iter)) {
182                 GString *output = g_string_new ("");
183                 GSList *toggled_tags;
184                 GSList *node;
185
186                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
187                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
188                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
189                         GtkTextTag *tag = (GtkTextTag *) node->data;
190                         const gchar *name;
191                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
192                         output = g_string_append (output, name);
193                         g_string_append (output, " ");
194                 }
195                 output = g_string_append (output, "] OPENED [ ");
196                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
197                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
198                         GtkTextTag *tag = (GtkTextTag *) node->data;
199                         const gchar *name;
200                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
201                         output = g_string_append (output, name);
202                         g_string_append (output, " ");
203                 }
204                 output = g_string_append (output, "]\n");
205                 g_message ("%s", output->str);
206                 g_string_free (output, TRUE);
207                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
208         }
209         g_message ("END BUFFER");
210 #endif
211 }
212
213 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
214         { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
215 };
216
217
218 /* static gboolean */
219 /* on_key_pressed (GtkWidget *self, */
220 /*              GdkEventKey *event, */
221 /*              gpointer user_data); */
222
223 /* list my signals */
224 enum {
225         /* MY_SIGNAL_1, */
226         /* MY_SIGNAL_2, */
227         LAST_SIGNAL
228 };
229
230 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
231 struct _ModestMsgEditWindowPrivate {
232         GtkWidget   *msg_body;
233         GtkWidget   *frame;
234         GtkWidget   *header_box;
235         
236         ModestPairList *from_field_protos;
237         GtkWidget   *from_field;
238         gchar       *original_account_name;
239         
240         GtkWidget   *to_field;
241         GtkWidget   *cc_field;
242         GtkWidget   *bcc_field;
243         GtkWidget   *subject_field;
244         GtkWidget   *attachments_view;
245         GtkWidget   *priority_icon;
246         GtkWidget   *add_attachment_button;
247
248         GtkWidget   *cc_caption;
249         GtkWidget   *bcc_caption;
250         gboolean     update_caption_visibility;
251         GtkWidget   *attachments_caption;
252
253         GtkTextBuffer *text_buffer;
254
255         GtkWidget   *font_size_toolitem;
256         GtkWidget   *font_face_toolitem;
257         GtkWidget   *font_color_button;
258         GtkWidget   *font_color_toolitem;
259         GSList      *font_items_group;
260         GtkWidget   *font_tool_button_label;
261         GSList      *size_items_group;
262         GtkWidget   *size_tool_button_label;
263
264         GtkWidget   *find_toolbar;
265         gchar       *last_search;
266
267         GtkWidget   *font_dialog;
268
269         GtkWidget   *pannable;
270         guint        correct_scroll_idle;
271         guint        scroll_drag_timeout_id;
272         gdouble      last_upper;
273
274         gint next_cid;
275         TnyList *attachments;
276         TnyList *images;
277         guint64 images_size;
278         gint images_count;
279
280         TnyHeaderFlags priority_flags;
281
282         gboolean    can_undo, can_redo;
283         gulong      clipboard_change_handler_id;
284         gulong      default_clipboard_change_handler_id;
285         gulong      account_removed_handler_id;
286         guint       clipboard_owner_idle;
287         gchar       *clipboard_text;
288
289         TnyMsg      *draft_msg;
290         TnyMsg      *outbox_msg;
291         gchar       *msg_uid;
292
293         gboolean    sent;
294
295         GtkWidget   *app_menu;
296         GtkWidget   *cc_button;
297         GtkWidget   *bcc_button;
298 };
299
300 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
301                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
302                                                     ModestMsgEditWindowPrivate))
303 /* globals */
304 static GtkWindowClass *parent_class = NULL;
305
306 /* uncomment the following if you have defined any signals */
307 /* static guint signals[LAST_SIGNAL] = {0}; */
308
309 GType
310 modest_msg_edit_window_get_type (void)
311 {
312         static GType my_type = 0;
313         if (!my_type) {
314                 static const GTypeInfo my_info = {
315                         sizeof(ModestMsgEditWindowClass),
316                         NULL,           /* base init */
317                         NULL,           /* base finalize */
318                         (GClassInitFunc) modest_msg_edit_window_class_init,
319                         NULL,           /* class finalize */
320                         NULL,           /* class data */
321                         sizeof(ModestMsgEditWindow),
322                         1,              /* n_preallocs */
323                         (GInstanceInitFunc) modest_msg_edit_window_init,
324                         NULL
325                 };
326                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
327                                                   "ModestMsgEditWindow",
328                                                   &my_info, 0);
329
330         }
331         return my_type;
332 }
333
334 static void
335 save_state (ModestWindow *self)
336 {
337         modest_widget_memory_save (modest_runtime_get_conf(),
338                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
339 }
340
341
342 static void
343 restore_settings (ModestMsgEditWindow *self)
344 {
345         ModestConf *conf = NULL;
346         GtkAction *action;
347         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
348
349         conf = modest_runtime_get_conf ();
350
351         /* Dim at start clipboard actions */
352         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
353         gtk_action_set_sensitive (action, FALSE);
354         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
355         gtk_action_set_sensitive (action, FALSE);
356         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
357         gtk_action_set_sensitive (action, FALSE);
358
359         modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
360 }
361
362
363 static void
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
365 {
366         GObjectClass *gobject_class;
367         ModestWindowClass *modest_window_class;
368         gobject_class = (GObjectClass*) klass;
369         modest_window_class = (ModestWindowClass*) klass;
370
371         parent_class            = g_type_class_peek_parent (klass);
372         gobject_class->finalize = modest_msg_edit_window_finalize;
373
374         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375         modest_window_class->save_state_func = save_state;
376         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
377
378         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 }
380
381 static void
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
383 {
384         ModestMsgEditWindowPrivate *priv;
385         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
386
387         priv->msg_body      = NULL;
388         priv->frame         = NULL;
389         priv->from_field    = NULL;
390         priv->to_field      = NULL;
391         priv->cc_field      = NULL;
392         priv->bcc_field     = NULL;
393         priv->subject_field = NULL;
394         priv->attachments   = TNY_LIST (tny_simple_list_new ());
395         priv->images        = TNY_LIST (tny_simple_list_new ());
396         priv->images_size   = 0;
397         priv->images_count  = 0;
398         priv->next_cid      = 0;
399
400         priv->cc_caption    = NULL;
401         priv->bcc_caption    = NULL;
402         priv->update_caption_visibility = FALSE;
403
404         priv->priority_flags = 0;
405
406         priv->find_toolbar = NULL;
407         priv->last_search = NULL;
408
409         priv->draft_msg = NULL;
410         priv->outbox_msg = NULL;
411         priv->msg_uid = NULL;
412
413         priv->can_undo = FALSE;
414         priv->can_redo = FALSE;
415         priv->clipboard_change_handler_id = 0;
416         priv->default_clipboard_change_handler_id = 0;
417         priv->account_removed_handler_id = 0;
418         priv->clipboard_owner_idle = 0;
419         priv->clipboard_text = NULL;
420         priv->sent = FALSE;
421
422         priv->scroll_drag_timeout_id = 0;
423         priv->correct_scroll_idle = 0;
424         priv->last_upper = 0.0;
425
426         priv->font_dialog = NULL;
427         priv->app_menu = NULL;
428
429         if (!is_wp_text_buffer_started) {
430                 is_wp_text_buffer_started = TRUE;
431                 wp_text_buffer_library_init ();
432         }
433
434         init_window (obj);
435         
436         hildon_program_add_window (hildon_program_get_instance(),
437                                    HILDON_WINDOW(obj));
438 }
439
440
441 /** 
442  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
443  */
444 static ModestPairList*
445 get_transports (void)
446 {
447         GSList *transports = NULL;
448         
449         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
450         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
451                                                              TRUE /* only enabled accounts. */); 
452                                                 
453         GSList *cursor = accounts;
454         while (cursor) {
455                 gchar *account_name = cursor->data;
456                 gchar *from_string  = NULL;
457                 if (account_name) {
458                         from_string = modest_account_mgr_get_from_string (account_mgr,
459                                                                           account_name);
460                 }
461                 
462                 if (from_string && account_name) {
463                         gchar *name = account_name;
464                         ModestPair *pair = modest_pair_new ((gpointer) name,
465                                                 (gpointer) from_string , TRUE);
466                         transports = g_slist_prepend (transports, pair);
467                 }
468                 
469                 cursor = cursor->next;
470         }
471         g_slist_free (accounts); /* only free the accounts, not the elements,
472                                   * because they are used in the pairlist */
473         return transports;
474 }
475
476 static void window_focus (GtkWindow *window,
477                           GtkWidget *widget,
478                           gpointer userdata)
479 {
480         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
481 }
482
483 gboolean
484 scroll_drag_timeout (gpointer userdata)
485 {
486         ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
487         ModestMsgEditWindowPrivate *priv;
488
489         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
490
491         correct_scroll_without_drag_check (win, TRUE);
492
493         priv->scroll_drag_timeout_id = 0;
494
495         return FALSE;
496 }
497
498 static gboolean 
499 correct_scroll_without_drag_check_idle (gpointer userdata)
500 {
501         ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
502         ModestMsgEditWindowPrivate *priv;
503         GtkTextIter iter;
504         GdkRectangle rectangle;
505         gdouble new_value;
506         gint offset;
507         GtkTextMark *insert;
508
509         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
510         
511         insert = gtk_text_buffer_get_insert (priv->text_buffer);
512         gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
513
514         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
515         offset = priv->msg_body->allocation.y;
516
517         new_value = (offset + rectangle.y);
518
519         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (priv->pannable), -1, new_value);
520
521         priv->correct_scroll_idle = 0;
522         return FALSE;
523 }
524
525 static void
526 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
527 {
528         ModestMsgEditWindowPrivate *priv;
529
530         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
531
532         if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
533                 return;
534
535         if (priv->correct_scroll_idle > 0) {
536                 return;
537         }
538
539         priv->correct_scroll_idle = g_idle_add ((GSourceFunc) correct_scroll_without_drag_check_idle,
540                                                 (gpointer) w);
541 }
542
543 static void
544 correct_scroll (ModestMsgEditWindow *w)
545 {
546         ModestMsgEditWindowPrivate *priv;
547
548         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
549         if (gtk_grab_get_current () == priv->msg_body) {
550                 if (priv->scroll_drag_timeout_id == 0) {
551                         priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
552                                                                       (gpointer) w);
553                 }
554                 return;
555         }
556
557         correct_scroll_without_drag_check (w, TRUE);
558 }
559
560 static void
561 text_buffer_end_user_action (GtkTextBuffer *buffer,
562                              ModestMsgEditWindow *userdata)
563 {
564
565         correct_scroll (userdata);
566 }
567
568 static void
569 text_buffer_mark_set (GtkTextBuffer *buffer,
570                       GtkTextIter *iter,
571                       GtkTextMark *mark,
572                       ModestMsgEditWindow *userdata)
573 {
574         gtk_text_buffer_begin_user_action (buffer);
575         gtk_text_buffer_end_user_action (buffer);
576 }
577
578 static void
579 cut_clipboard_check (GtkTextView *text_view,
580                      gpointer userdata)
581 {
582         GtkTextBuffer *buffer;
583         
584         buffer = gtk_text_view_get_buffer (text_view);
585         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
586                 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
587         }
588 }
589
590 static void
591 copy_clipboard_check (GtkTextView *text_view,
592                      gpointer userdata)
593 {
594         GtkTextBuffer *buffer;
595         
596         buffer = gtk_text_view_get_buffer (text_view);
597         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
598                 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
599         }
600 }
601
602 static void
603 attachment_deleted (ModestAttachmentsView *attachments_view,
604                     gpointer user_data)
605 {
606         modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
607                                                    NULL);
608 }
609
610 static void
611 connect_signals (ModestMsgEditWindow *obj)
612 {
613         ModestMsgEditWindowPrivate *priv;
614
615         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
616
617         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
618                           G_CALLBACK (text_buffer_refresh_attributes), obj);
619         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
620                           G_CALLBACK (text_buffer_can_undo), obj);
621         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
622                           G_CALLBACK (text_buffer_can_redo), obj);
623         g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
624                           G_CALLBACK (body_changed), obj);
625         g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
626                           G_CALLBACK (body_changed), obj);
627         g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
628                           G_CALLBACK (text_buffer_end_user_action), obj);
629         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
630                           G_CALLBACK (text_buffer_mark_set), obj);
631         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
632                                 G_CALLBACK (text_buffer_apply_tag), obj);
633         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
634                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
635         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
636                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
637         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
638                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
639
640         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
641                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
642
643         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
644                           G_CALLBACK (msg_body_focus), obj);
645         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
646                           G_CALLBACK (msg_body_focus), obj);
647         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
648         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
649                           "changed", G_CALLBACK (recpt_field_changed), obj);
650         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
651                           "changed", G_CALLBACK (recpt_field_changed), obj);
652         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
653                           "changed", G_CALLBACK (recpt_field_changed), obj);
654         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
655         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
656         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
657
658         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
659         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
660  
661         priv->clipboard_change_handler_id = 
662                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
663                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
664         priv->default_clipboard_change_handler_id = 
665                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
666                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
667
668         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
669         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
670         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
671 }
672
673 static void
674 init_wp_text_view_style ()
675 {
676         static gboolean initialized = FALSE;
677
678         if (!initialized) {
679                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
680                 initialized = TRUE;
681         }
682 }       
683
684 static void
685 init_window (ModestMsgEditWindow *obj)
686 {
687         GtkWidget *to_caption, *subject_caption;
688         GtkWidget *main_vbox;
689         ModestMsgEditWindowPrivate *priv;
690         GtkActionGroup *action_group;
691         ModestWindowPrivate *parent_priv;
692         GdkPixbuf *window_icon = NULL;
693         GError *error = NULL;
694
695         GtkSizeGroup *title_size_group;
696         GtkSizeGroup *value_size_group;
697         GtkWidget *subject_box;
698         GtkWidget *attachment_icon;
699         GtkWidget *window_box;
700 #if (GTK_MINOR_VERSION >= 10)
701         GdkAtom deserialize_type;
702 #endif
703
704         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
705         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
706
707         parent_priv->ui_manager = gtk_ui_manager_new();
708         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
709         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
710
711         /* Add common actions */
712         gtk_action_group_add_actions (action_group,
713                                       modest_msg_edit_action_entries,
714                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
715                                       obj);
716         gtk_action_group_add_actions (action_group,
717                                       hildon2_msg_edit_action_entries,
718                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
719                                       obj);
720         gtk_action_group_add_toggle_actions (action_group,
721                                              modest_msg_edit_toggle_action_entries,
722                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
723                                              obj);
724         gtk_action_group_add_radio_actions (action_group,
725                                             modest_msg_edit_alignment_radio_action_entries,
726                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
727                                             GTK_JUSTIFY_LEFT,
728                                             G_CALLBACK (modest_ui_actions_on_change_justify),
729                                             obj);
730         gtk_action_group_add_radio_actions (action_group,
731                                             modest_msg_edit_priority_action_entries,
732                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
733                                             0,
734                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
735                                             obj);
736         gtk_action_group_add_radio_actions (action_group,
737                                             modest_msg_edit_file_format_action_entries,
738                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
739                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
740                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
741                                             obj);
742         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
743         g_object_unref (action_group);
744
745         /* Load the UI definition */
746         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
747                                          &error);
748         if (error != NULL) {
749                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
750                 g_clear_error (&error);
751         }
752
753         /* Add accelerators */
754         gtk_window_add_accel_group (GTK_WINDOW (obj), 
755                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
756
757         parent_priv->menubar = NULL;
758
759         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
760         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
761
762         /* Note: This ModestPairList* must exist for as long as the picker
763          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
764          * so it can't know how to manage its memory. */ 
765         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
766                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
767                                                           NULL, g_str_equal);
768         modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group, 
769                                                _("mail_va_from"), priv->from_field);
770
771         priv->to_field      = modest_recpt_editor_new ();
772         priv->cc_field      = modest_recpt_editor_new ();
773         priv->bcc_field     = modest_recpt_editor_new ();
774         subject_box = gtk_hbox_new (FALSE, 0);
775         priv->priority_icon = gtk_image_new ();
776         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
777         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
778         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
779         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
780         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
781                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
782         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
783         priv->add_attachment_button = gtk_button_new ();
784         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
785         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
786         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
787         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 0.5);
788         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
789         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
790         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
791         priv->attachments_view = modest_attachments_view_new (NULL);
792         
793         priv->header_box = gtk_vbox_new (FALSE, 0);
794         
795         to_caption = modest_maemo_utils_create_captioned_with_size_type 
796                 (title_size_group, value_size_group,
797                  _("mail_va_to"), FALSE, priv->to_field,
798                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
799         priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type 
800                 (title_size_group, value_size_group,
801                  _("mail_va_cc"), FALSE, priv->cc_field,
802                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
803         priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
804                 (title_size_group, value_size_group,
805                  _("mail_va_hotfix1"), FALSE, priv->bcc_field,
806                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
807         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
808                                                                _("mail_va_subject"), FALSE, subject_box);
809         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
810                                                                                         _("mail_va_attachment"), 
811                                                                                         FALSE,
812                                                                                         priv->attachments_view,
813                                                                                         HILDON_SIZE_AUTO_WIDTH |
814                                                                                         HILDON_SIZE_AUTO_HEIGHT);
815         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
816         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
817         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
818         g_object_unref (title_size_group);
819         g_object_unref (value_size_group);
820
821         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
822         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
823         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
824         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
825         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
826         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
827         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
828
829         init_wp_text_view_style ();
830
831         priv->msg_body = wp_text_view_new ();
832         
833
834         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
835         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
836         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
837         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
838 #if (GTK_MINOR_VERSION >= 10)
839         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
840         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
841                                                                        NULL);
842         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
843                                                          deserialize_type, TRUE);
844 #endif
845         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
846
847         priv->find_toolbar = hildon_find_toolbar_new (NULL);
848         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
849
850 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
851
852         priv->pannable = hildon_pannable_area_new ();
853         
854         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
855
856         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
857         priv->frame = gtk_frame_new (NULL);
858         gtk_box_pack_start (GTK_BOX(main_vbox), priv->frame, TRUE, TRUE, 0);
859
860         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), main_vbox);
861         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
862         
863         window_box = gtk_vbox_new (FALSE, 0);
864         gtk_container_add (GTK_CONTAINER(obj), window_box);
865
866         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
867
868         gtk_container_add (GTK_CONTAINER (priv->frame), priv->msg_body);
869
870         /* Set window icon */
871         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
872         if (window_icon) {
873                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
874                 g_object_unref (window_icon);
875         }       
876 }
877         
878 static void
879 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
880 {
881         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
882
883         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
884             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
885                                            priv->clipboard_change_handler_id))
886                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
887                                              priv->clipboard_change_handler_id);
888         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
889             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
890                                            priv->default_clipboard_change_handler_id))
891                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
892                                              priv->default_clipboard_change_handler_id);
893
894         if (priv->account_removed_handler_id && 
895             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
896                                            priv->account_removed_handler_id))
897                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
898                                            priv->account_removed_handler_id);
899 }
900
901 static void
902 modest_msg_edit_window_finalize (GObject *obj)
903 {
904         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
905         
906         /* Sanity check: shouldn't be needed, the window mgr should
907            call this function before */
908         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
909
910         if (priv->font_dialog != NULL) {
911                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
912         }
913
914         if (priv->clipboard_text != NULL) {
915                 g_free (priv->clipboard_text);
916                 priv->clipboard_text = NULL;
917         }
918         
919         if (priv->draft_msg != NULL) {
920                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
921                 if (TNY_IS_HEADER (header)) {
922                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
923                         modest_window_mgr_unregister_header (mgr, header);
924                 }
925                 g_object_unref (priv->draft_msg);
926                 priv->draft_msg = NULL;
927         }
928         if (priv->outbox_msg != NULL) {
929                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
930                 if (TNY_IS_HEADER (header)) {
931                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
932                         modest_window_mgr_unregister_header (mgr, header);
933                 }
934                 g_object_unref (priv->outbox_msg);
935                 priv->outbox_msg = NULL;
936         }
937         if (priv->correct_scroll_idle > 0) {
938                 g_source_remove (priv->correct_scroll_idle);
939                 priv->correct_scroll_idle = 0;
940         }
941         if (priv->scroll_drag_timeout_id > 0) {
942                 g_source_remove (priv->scroll_drag_timeout_id);
943                 priv->scroll_drag_timeout_id = 0;
944         }
945         if (priv->clipboard_owner_idle > 0) {
946                 g_source_remove (priv->clipboard_owner_idle);
947                 priv->clipboard_owner_idle = 0;
948         }
949         if (priv->original_account_name)
950                 g_free (priv->original_account_name);
951         g_free (priv->msg_uid);
952         g_free (priv->last_search);
953         g_slist_free (priv->font_items_group);
954         g_slist_free (priv->size_items_group);
955         g_object_unref (priv->attachments);
956         g_object_unref (priv->images);
957
958         /* This had to stay alive for as long as the picker that used it: */
959         modest_pair_list_free (priv->from_field_protos);
960         
961         G_OBJECT_CLASS(parent_class)->finalize (obj);
962 }
963
964 static GdkPixbuf *
965 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
966 {
967         GdkPixbufLoader *loader;
968         GdkPixbuf *pixbuf;
969         guint64 size;
970         
971         size = 0;
972
973         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
974
975         if (loader == NULL) {
976                 if (stream_size)
977                         *stream_size = 0;
978                 return NULL;
979         }
980
981         tny_stream_reset (TNY_STREAM (stream));
982         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
983                 GError *error = NULL;
984                 unsigned char read_buffer[128];
985                 gint readed;
986                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
987                 size += readed;
988                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
989                         if (error)
990                                 g_error_free (error);
991                         break;
992                 }
993         }
994
995         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
996         if (pixbuf) 
997                 g_object_ref (pixbuf);
998         gdk_pixbuf_loader_close (loader, NULL);
999         g_object_unref (loader);
1000
1001         if (!pixbuf)
1002                 return NULL;
1003
1004         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1005                 GdkPixbuf *new_pixbuf;
1006                 gint new_height;
1007                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1008                         gdk_pixbuf_get_width (pixbuf);
1009                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1010                 g_object_unref (pixbuf);
1011                 pixbuf = new_pixbuf;
1012         }
1013
1014         if (stream_size)
1015                 *stream_size = size;
1016
1017         return pixbuf;
1018 }
1019
1020 static void
1021 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1022 {
1023         ModestMsgEditWindowPrivate *priv;
1024         TnyIterator *iter;
1025
1026         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1027
1028         for (iter = tny_list_create_iterator (attachments);
1029              !tny_iterator_is_done (iter);
1030              tny_iterator_next (iter)) {
1031                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1032                 const gchar *cid = tny_mime_part_get_content_id (part);
1033                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1034                 if ((cid != NULL)&&(mime_type != NULL)) {
1035                         guint64 stream_size;
1036                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1037                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1038
1039
1040                         g_object_unref (stream);
1041
1042                         if (pixbuf != NULL) {
1043                                 priv->images_count ++;
1044                                 priv->images_size += stream_size;
1045                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1046                                 g_object_unref (pixbuf);
1047                         }
1048                 }
1049                 g_object_unref (part);
1050         }
1051         g_object_unref (iter);
1052 }
1053
1054 static void
1055 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1056 {
1057         TnyMimePart *parent = NULL;
1058         const gchar *content_type = NULL;
1059         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1060
1061         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1062         
1063         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1064                 parent = g_object_ref (msg);
1065         } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1066                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1067                 TnyIterator *iter;
1068
1069                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1070                 iter = tny_list_create_iterator (parts);
1071                 while (!tny_iterator_is_done (iter)) {
1072                         TnyMimePart *part;
1073                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1074                         content_type = tny_mime_part_get_content_type (part);
1075                         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1076                                 parent = part;
1077                                 break;
1078                         } else {
1079                                 g_object_unref (part);
1080                         }
1081                         tny_iterator_next (iter);
1082                 }
1083                 g_object_unref (iter);
1084                 g_object_unref (parts);
1085         }
1086
1087         if (parent != NULL) {
1088                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1089                 TnyIterator *iter;
1090
1091                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1092                 iter = tny_list_create_iterator (parts);
1093                 while (!tny_iterator_is_done (iter)) {
1094                         TnyMimePart *part;
1095                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1096                         content_type = tny_mime_part_get_content_type (part);
1097                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1098                                 tny_list_prepend (priv->images, (GObject *) part);
1099                         } 
1100                         g_object_unref (part);
1101                         tny_iterator_next (iter);
1102                 }
1103                 g_object_unref (iter);
1104                 g_object_unref (parts);
1105                 g_object_unref (parent);
1106         }
1107 }
1108
1109 static void
1110 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1111 {
1112         TnyIterator *iter;
1113         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1114
1115         for (iter = tny_list_create_iterator (attachments) ; 
1116              !tny_iterator_is_done (iter);
1117              tny_iterator_next (iter)) {
1118                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1119                 const gchar *cid = tny_mime_part_get_content_id (part);
1120                 if (cid != NULL) {
1121                         char *invalid = NULL;
1122                         gint int_cid = strtol (cid, &invalid, 10);
1123                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1124                                 priv->next_cid = int_cid + 1;
1125                         }
1126                 }
1127                 g_object_unref (part);
1128         }
1129         g_object_unref (iter);
1130 }
1131
1132 static void
1133 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1134 {
1135         TnyHeader *header;
1136         gchar *to, *cc, *bcc, *subject;
1137         gchar *body;
1138         ModestMsgEditWindowPrivate *priv;
1139         ModestWindowPrivate *parent_priv;
1140         GtkTextIter iter;
1141         TnyHeaderFlags priority_flags;
1142         TnyFolder *msg_folder;
1143         gboolean is_html = FALSE;
1144         gboolean field_view_set;
1145         
1146         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1147         g_return_if_fail (TNY_IS_MSG (msg));
1148
1149         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1150         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1151
1152         header = tny_msg_get_header (msg);
1153         to      = tny_header_dup_to (header);
1154         cc      = tny_header_dup_cc (header);
1155         bcc     = tny_header_dup_bcc (header);
1156         subject = tny_header_dup_subject (header);
1157         priority_flags = tny_header_get_priority (header);
1158
1159         if (to)
1160                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
1161
1162         field_view_set = TRUE;
1163         if (cc) {
1164                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
1165                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1166                 gtk_widget_show (priv->cc_caption);
1167         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1168                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1169                 gtk_widget_hide (priv->cc_caption);
1170                 field_view_set = FALSE;
1171         }
1172         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1173
1174         field_view_set = TRUE;
1175         if (bcc) {
1176                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1177                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1178                 gtk_widget_show (priv->bcc_caption);
1179         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1180                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1181                 gtk_widget_hide (priv->bcc_caption);
1182                 field_view_set = FALSE;
1183         }
1184         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1185
1186
1187         if (subject)
1188                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1189         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1190                                                    priority_flags);
1191
1192         update_window_title (self);
1193
1194         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1195         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1196
1197         if ((body == NULL)||(body[0] == '\0')) {
1198                 g_free (body);
1199                 body = modest_text_utils_convert_to_html ("");
1200                 is_html = FALSE;
1201         }
1202         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1203         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1204                                             (gchar *) body,
1205                                             strlen (body));
1206         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1207         g_free (body);
1208
1209         /* Add attachments to the view */
1210         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1211         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1212         if (tny_list_get_length (priv->attachments) == 0) {
1213                 gtk_widget_hide (priv->attachments_caption);
1214         } else {
1215                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1216                 gtk_widget_show_all (priv->attachments_caption);
1217         }
1218         get_related_images (self, msg);
1219         update_next_cid (self, priv->attachments);
1220         update_next_cid (self, priv->images);
1221         replace_with_images (self, priv->images);
1222
1223         if (preserve_is_rich && !is_html) {
1224                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1225         /* Get the default format required from configuration */
1226         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1227                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1228         }
1229
1230         /* Set the default focus depending on having already a To: field or not */
1231         if ((!to)||(*to == '\0')) {
1232                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1233         } else {
1234                 gtk_widget_grab_focus (priv->msg_body);
1235         }
1236
1237         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1238
1239         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1240         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1241
1242         modest_msg_edit_window_set_modified (self, FALSE);
1243
1244         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1245         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1246         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1247         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1248
1249         if (priv->msg_uid) {
1250                 g_free (priv->msg_uid);
1251                 priv->msg_uid = NULL;
1252         }
1253
1254         /* we should set a reference to the incoming message if it is a draft */
1255         msg_folder = tny_msg_get_folder (msg);
1256         if (msg_folder) {               
1257                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1258                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1259                         if (type == TNY_FOLDER_TYPE_INVALID)
1260                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1261                         
1262                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1263                                 priv->draft_msg = g_object_ref(msg);
1264                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1265                                 priv->outbox_msg = g_object_ref(msg);
1266                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1267                 }
1268                 g_object_unref (msg_folder);
1269         }
1270
1271         g_free (to);
1272         g_free (subject);
1273         g_free (cc);
1274         g_free (bcc);
1275 }
1276
1277 static void
1278 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1279                                 gpointer data)
1280 {
1281         GList *item_children, *node;
1282         GtkWidget *bin_child;
1283
1284         bin_child = gtk_bin_get_child (GTK_BIN(item));
1285
1286         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1287         
1288         for (node = item_children; node != NULL; node = g_list_next (node)) {
1289                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1290                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1291                 }
1292         }
1293         g_list_free (item_children);
1294 }
1295
1296 static void
1297 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1298 {
1299         GtkWidget *box;
1300         GList *item_children, *node;
1301
1302         box = gtk_bin_get_child (GTK_BIN (item));
1303         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1304         item_children = gtk_container_get_children (GTK_CONTAINER (box));
1305         
1306         for (node = item_children; node != NULL; node = g_list_next (node)) {
1307                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1308                 if (GTK_IS_TOGGLE_BUTTON (node->data))
1309                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1310                 else if (GTK_IS_BUTTON (node->data))
1311                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1312         }
1313         g_list_free (item_children);
1314 }
1315
1316
1317 static void
1318 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1319 {
1320         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1321         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1322         GtkWidget *placeholder;
1323         GtkWidget *tool_item;
1324         gint insert_index;
1325         gchar size_text[5];
1326         gint size_index;
1327         gint font_index;
1328         GtkWidget *sizes_menu;
1329         GtkWidget *fonts_menu;
1330         GSList *radio_group = NULL;
1331         GSList *node = NULL;
1332         gchar *markup;
1333
1334         /* Toolbar */
1335         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1336         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1337
1338         /* Font color placeholder */
1339         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1340         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1341
1342         /* font color */
1343         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1344         priv->font_color_button = hildon_color_button_new ();
1345         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1346         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1347         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1348         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1349         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1350         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1351         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1352                                   "notify::color", 
1353                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1354                                   window);
1355
1356         /* Font size and face placeholder */
1357         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1358         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1359         /* font_size */
1360         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1361         priv->size_tool_button_label = gtk_label_new (NULL);
1362         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1363         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1364                               size_text,"</span>", NULL);
1365         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1366         g_free (markup);
1367         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1368         sizes_menu = gtk_menu_new ();
1369         priv->size_items_group = NULL;
1370         radio_group = NULL;
1371         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1372                 GtkWidget *size_menu_item;
1373
1374                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1375                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1376                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1377                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1378                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1379                 gtk_widget_show (size_menu_item);
1380
1381                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1382                         
1383         }
1384
1385         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1386                 GtkWidget *item = (GtkWidget *) node->data;
1387                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1388                                   window);
1389         }
1390
1391         priv->size_items_group = g_slist_reverse (priv->size_items_group);
1392         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1393         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1394         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1395         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1396         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1397         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1398         priv->font_size_toolitem = tool_item;
1399
1400         /* font face */
1401         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1402         priv->font_tool_button_label = gtk_label_new (NULL);
1403         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1404         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1405         g_free(markup);
1406         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1407         fonts_menu = gtk_menu_new ();
1408         priv->font_items_group = NULL;
1409         radio_group = NULL;
1410         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1411                 GtkWidget *font_menu_item;
1412                 GtkWidget *child_label;
1413
1414                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1415                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1416                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
1417                                       wp_get_font_name (font_index), "</span>", NULL);
1418                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1419                 g_free (markup);
1420                 
1421                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1422                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1423                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1424                 gtk_widget_show (font_menu_item);
1425
1426                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1427                         
1428         }
1429         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1430                 GtkWidget *item = (GtkWidget *) node->data;
1431                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1432                                   window);
1433         }
1434         priv->font_items_group = g_slist_reverse (priv->font_items_group);
1435         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1436         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1437         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1438         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1439         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1440         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1441         priv->font_face_toolitem = tool_item;
1442
1443         /* Set expand and homogeneous for remaining items */
1444         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1445         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1446         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1447         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1448         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1449         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1450         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1451         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1452         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1453
1454         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1455            will not show the tool items added to the placeholders) */
1456         gtk_widget_show_all (parent_priv->toolbar);
1457
1458         /* Set the no show all *after* showing all items. We do not
1459            want the toolbar to be shown with a show all because it
1460            could go agains the gconf setting regarding showing or not
1461            the toolbar of the editor window */
1462         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1463 }
1464
1465
1466
1467 ModestWindow*
1468 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1469 {
1470         GObject *obj;
1471         ModestWindowPrivate *parent_priv;
1472         ModestMsgEditWindowPrivate *priv;
1473         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1474         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1475         ModestWindowMgr *mgr = NULL;
1476
1477         g_return_val_if_fail (msg, NULL);
1478         g_return_val_if_fail (account_name, NULL);
1479
1480         mgr = modest_runtime_get_window_mgr ();
1481         
1482         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1483
1484         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1485         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1486
1487         /* Menubar. Update the state of some toggles */
1488         priv->from_field_protos = get_transports ();
1489         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1490         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1491         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1492                                  _("mail_va_from"));
1493         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1494                                  hildon_touch_selector_get_current_text 
1495                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1496         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1497         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1498
1499         /* Init window */
1500         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1501
1502         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1503                 
1504         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1505
1506         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1507
1508         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1509         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1510         /* Add common dimming rules */
1511         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1512                                               modest_msg_edit_window_toolbar_dimming_entries,
1513                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1514                                               MODEST_WINDOW (obj));
1515         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1516                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1517                                                     MODEST_WINDOW (obj));
1518         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1519                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1520                                                     MODEST_WINDOW (obj));
1521         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1522                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1523                                                     MODEST_WINDOW (obj));
1524         /* Insert dimming rules group for this window */
1525         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1526         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1527
1528         /* Setup app menu */
1529         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1530
1531         /* Checks the dimming rules */
1532         g_object_unref (toolbar_rules_group);
1533         g_object_unref (clipboard_rules_group);
1534         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1535
1536         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1537
1538         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1539         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1540         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1541         priv->update_caption_visibility = TRUE;
1542
1543         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1544
1545         /* Track account-removed signal, this window should be closed
1546            in the case we're creating a mail associated to the account
1547            that is deleted */
1548         priv->account_removed_handler_id = 
1549                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1550                                   "account_removed",
1551                                   G_CALLBACK(on_account_removed),
1552                                   obj);
1553
1554         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1555
1556         return (ModestWindow*) obj;
1557 }
1558
1559 static gint
1560 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1561 {
1562         GString **string_buffer = (GString **) user_data;
1563
1564         *string_buffer = g_string_append (*string_buffer, buffer);
1565    
1566         return 0;
1567 }
1568
1569 /**
1570  * @result: A new string which should be freed with g_free().
1571  */
1572 static gchar *
1573 get_formatted_data (ModestMsgEditWindow *edit_window)
1574 {
1575         ModestMsgEditWindowPrivate *priv;
1576         GString *string_buffer = g_string_new ("");
1577         
1578         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1579
1580         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1581
1582         modest_text_utils_hyperlinkify (string_buffer);
1583
1584         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1585
1586         return g_string_free (string_buffer, FALSE);
1587                                                                         
1588 }
1589
1590 MsgData * 
1591 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1592 {
1593         MsgData *data;
1594         const gchar *account_name;
1595         ModestMsgEditWindowPrivate *priv;
1596         TnyIterator *att_iter;
1597         
1598         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1599
1600         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1601                                                                         
1602         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1603         g_return_val_if_fail (account_name, NULL);
1604         
1605         
1606         /* don't free these (except from) */
1607         data = g_slice_new0 (MsgData);
1608         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1609                                                              account_name);
1610         data->account_name = g_strdup (account_name);
1611         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1612         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1613         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1614         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1615         if (priv->draft_msg) {
1616                 data->draft_msg = g_object_ref (priv->draft_msg);
1617         } else if (priv->outbox_msg) {
1618                 data->draft_msg = g_object_ref (priv->outbox_msg);
1619         } else {
1620                 data->draft_msg = NULL;
1621         }
1622
1623         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1624         GtkTextIter b, e;
1625         gtk_text_buffer_get_bounds (buf, &b, &e);
1626         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1627
1628         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1629                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1630         else
1631                 data->html_body = NULL;
1632
1633         /* deep-copy the data */
1634         att_iter = tny_list_create_iterator (priv->attachments);
1635         data->attachments = NULL;
1636         while (!tny_iterator_is_done (att_iter)) {
1637                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1638                 if (!(TNY_IS_MIME_PART(part))) {
1639                         g_warning ("strange data in attachment list");
1640                         g_object_unref (part);
1641                         tny_iterator_next (att_iter);
1642                         continue;
1643                 }
1644                 data->attachments = g_list_append (data->attachments,
1645                                                    part);
1646                 tny_iterator_next (att_iter);
1647         }
1648         g_object_unref (att_iter);
1649
1650         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1651         att_iter = tny_list_create_iterator (priv->images);
1652         data->images = NULL;
1653         while (!tny_iterator_is_done (att_iter)) {
1654                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1655                 const gchar *cid;
1656                 if (!(TNY_IS_MIME_PART(part))) {
1657                         g_warning ("strange data in attachment list");
1658                         g_object_unref (part);
1659                         tny_iterator_next (att_iter);
1660                         continue;
1661                 }
1662                 cid = tny_mime_part_get_content_id (part);
1663                 if (cid) {                      
1664                         gchar *image_tag_id;
1665                         GtkTextTag *image_tag;
1666                         GtkTextIter iter;
1667                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1668                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1669                         g_free (image_tag_id);
1670                         
1671                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1672                         if (image_tag && 
1673                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1674                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1675                                 data->images = g_list_append (data->images,
1676                                                               g_object_ref (part));
1677                 }
1678                 g_object_unref (part);
1679                 tny_iterator_next (att_iter);
1680         }
1681         g_object_unref (att_iter);
1682         
1683         data->priority_flags = priv->priority_flags;
1684
1685         return data;
1686 }
1687
1688
1689 static void
1690 unref_gobject (GObject *obj, gpointer data)
1691 {
1692         if (!G_IS_OBJECT(obj))
1693                 return;
1694         g_object_unref (obj);
1695 }
1696
1697 void 
1698 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1699                                                       MsgData *data)
1700 {
1701         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1702
1703         if (!data)
1704                 return;
1705
1706         g_free (data->to);
1707         g_free (data->cc);
1708         g_free (data->bcc);
1709         g_free (data->from);
1710         g_free (data->subject);
1711         g_free (data->plain_body);
1712         g_free (data->html_body);
1713         g_free (data->account_name);
1714         
1715         if (data->draft_msg != NULL) {
1716                 g_object_unref (data->draft_msg);
1717                 data->draft_msg = NULL;
1718         }
1719         
1720         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1721         g_list_free (data->attachments);
1722         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1723         g_list_free (data->images);
1724         
1725         g_slice_free (MsgData, data);
1726 }
1727
1728 void                    
1729 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1730                                        gint *parts_count,
1731                                        guint64 *parts_size)
1732 {
1733         ModestMsgEditWindowPrivate *priv;
1734
1735         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1736
1737         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1738
1739         /* TODO: add images */
1740         *parts_size += priv->images_size;
1741         *parts_count += priv->images_count;
1742
1743 }
1744
1745 ModestMsgEditFormat
1746 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1747 {
1748         gboolean rich_text;
1749         ModestMsgEditWindowPrivate *priv = NULL;
1750         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1751
1752         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1753
1754         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1755         if (rich_text)
1756                 return MODEST_MSG_EDIT_FORMAT_HTML;
1757         else
1758                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1759 }
1760
1761 void
1762 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1763                                    ModestMsgEditFormat format)
1764 {
1765         ModestMsgEditWindowPrivate *priv;
1766
1767         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1768         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1769
1770         switch (format) {
1771         case MODEST_MSG_EDIT_FORMAT_HTML:
1772                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1773                 break;
1774         case MODEST_MSG_EDIT_FORMAT_TEXT:
1775                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1776                 break;
1777         default:
1778                 g_return_if_reached ();
1779         }
1780 }
1781
1782 ModestMsgEditFormatState *
1783 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1784 {
1785         ModestMsgEditFormatState *format_state = NULL;
1786         ModestMsgEditWindowPrivate *priv;
1787         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1788
1789         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1790         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1791
1792         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1793
1794         format_state = g_new0 (ModestMsgEditFormatState, 1);
1795         format_state->bold = buffer_format->bold&0x1;
1796         format_state->italics = buffer_format->italic&0x1;
1797         format_state->bullet = buffer_format->bullet&0x1;
1798         format_state->color = buffer_format->color;
1799         format_state->font_size = buffer_format->font_size;
1800         format_state->font_family = wp_get_font_name (buffer_format->font);
1801         format_state->justification = buffer_format->justification;
1802         g_free (buffer_format);
1803
1804         return format_state;
1805  
1806 }
1807
1808 void
1809 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1810                                          const ModestMsgEditFormatState *format_state)
1811 {
1812         ModestMsgEditWindowPrivate *priv;
1813         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1814         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1815         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1816         g_return_if_fail (format_state != NULL);
1817
1818         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1819         gtk_widget_grab_focus (priv->msg_body);
1820         buffer_format->bold = (format_state->bold != FALSE);
1821         buffer_format->italic = (format_state->italics != FALSE);
1822         buffer_format->color = format_state->color;
1823         buffer_format->font_size = format_state->font_size;
1824         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1825         buffer_format->justification = format_state->justification;
1826         buffer_format->bullet = format_state->bullet;
1827
1828         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1829
1830         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1831         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1832         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1833         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1834         buffer_format->cs.font = (buffer_format->font != current_format->font);
1835         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1836         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1837
1838         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1839         if (buffer_format->cs.bold) {
1840                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1841                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1842         }
1843         if (buffer_format->cs.italic) {
1844                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1845                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1846         }
1847         if (buffer_format->cs.color) {
1848                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1849                                               GINT_TO_POINTER (&(buffer_format->color)));
1850         }
1851         if (buffer_format->cs.font_size) {
1852                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1853                                               GINT_TO_POINTER (buffer_format->font_size));
1854         }
1855         if (buffer_format->cs.justification) {
1856                 switch (buffer_format->justification) {
1857                 case GTK_JUSTIFY_LEFT:
1858                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1859                                                       GINT_TO_POINTER(TRUE));
1860                         break;
1861                 case GTK_JUSTIFY_CENTER:
1862                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1863                                                       GINT_TO_POINTER(TRUE));
1864                         break;
1865                 case GTK_JUSTIFY_RIGHT:
1866                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1867                                                       GINT_TO_POINTER(TRUE));
1868                         break;
1869                 default:
1870                         break;
1871                 }
1872                         
1873         }
1874         if (buffer_format->cs.font) {
1875                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1876                                               GINT_TO_POINTER (buffer_format->font));
1877         }
1878         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1879         if (buffer_format->cs.bullet) {
1880                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1881                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1882         }
1883 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1884         
1885         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1886         
1887         g_free (buffer_format);
1888         g_free (current_format);
1889
1890         /* Check dimming rules */
1891         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1892         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1893 }
1894
1895 static void
1896 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1897 {
1898         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1899         GtkAction *action;
1900         ModestWindowPrivate *parent_priv;
1901         ModestMsgEditWindowPrivate *priv;
1902         GtkWidget *new_size_menuitem;
1903         GtkWidget *new_font_menuitem;
1904         
1905         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1906         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1907
1908         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1909                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1910                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1911                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1912         } else {
1913                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1914                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1915                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1916         }
1917
1918         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1919
1920         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1921         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1922
1923         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1924         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1925
1926 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1927 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1928
1929         action = NULL;
1930         switch (buffer_format->justification)
1931         {
1932         case GTK_JUSTIFY_LEFT:
1933                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1934                 break;
1935         case GTK_JUSTIFY_CENTER:
1936                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1937                 break;
1938         case GTK_JUSTIFY_RIGHT:
1939                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1940                 break;
1941         default:
1942                 break;
1943         }
1944         
1945         if (action != NULL)
1946                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1947         
1948         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1949                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1950                                          window);
1951         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1952         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1953                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1954                                            window);
1955
1956         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1957                                                       buffer_format->font_size))->data);
1958         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1959                 GtkWidget *label;
1960                 gchar *markup;
1961
1962                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1963                 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1964                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1965                 g_free (markup);
1966                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1967                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1968                                                  window);
1969                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1970                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1971                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1972                                                    window);
1973         }
1974
1975         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1976                                                       buffer_format->font))->data);
1977         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1978                 GtkWidget *label;
1979                 gchar *markup;
1980
1981                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1982                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1983                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1984                 g_free (markup);
1985                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1986                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1987                                                  window);
1988                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1989                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1990                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1991                                                    window);
1992         }
1993
1994         g_free (buffer_format);
1995
1996 }
1997
1998 #ifdef MODEST_HILDON_VERSION_0
1999 void
2000 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2001 {
2002         
2003         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2004         ModestMsgEditWindowPrivate *priv;
2005         GtkWidget *dialog = NULL;
2006         gint response;
2007         GdkColor *new_color = NULL;
2008
2009         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2010         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2011         
2012         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2013         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2014         g_free (buffer_format);
2015
2016         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2017                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2018                 if (new_color != NULL) {
2019                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2020                                                       (gpointer) new_color);
2021                 }
2022         }
2023         gtk_widget_destroy (dialog);
2024 }
2025
2026
2027 void
2028 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2029 {
2030         
2031         ModestMsgEditWindowPrivate *priv;
2032         GtkWidget *dialog = NULL;
2033         gint response;
2034         GdkColor *old_color = NULL;
2035         const GdkColor *new_color = NULL;
2036         
2037         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2038         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2039         
2040         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2041         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2042
2043         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2044                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2045                 if (new_color != NULL)
2046                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2047         }
2048         gtk_widget_destroy (dialog);
2049
2050 }
2051
2052 #else 
2053 void
2054 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2055 {
2056         
2057         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2058         ModestMsgEditWindowPrivate *priv;
2059         GtkWidget *dialog = NULL;
2060
2061         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2062         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2063                 
2064         dialog = hildon_color_chooser_new ();
2065         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2066         g_free (buffer_format);
2067
2068         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2069                 GdkColor col;
2070                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2071                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2072                                               (gpointer) &col);
2073         }
2074         gtk_widget_destroy (dialog);
2075 }
2076
2077
2078 void
2079 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2080 {
2081         
2082         ModestMsgEditWindowPrivate *priv;
2083         GtkWidget *dialog = NULL;
2084         GdkColor *old_color = NULL;
2085         
2086         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2087         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2088         
2089         dialog = hildon_color_chooser_new ();
2090         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2091
2092         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2093                 GdkColor col;
2094                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2095                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2096         }
2097         gtk_widget_destroy (dialog);
2098 }
2099
2100 #endif /*!MODEST_HILDON_VERSION_0*/
2101
2102
2103
2104 static TnyStream*
2105 create_stream_for_uri (const gchar* uri)
2106 {
2107         if (!uri)
2108                 return NULL;
2109                 
2110         TnyStream *result = NULL;
2111
2112         GnomeVFSHandle *handle = NULL;
2113         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2114         if (test == GNOME_VFS_OK) {
2115                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2116                 /* Streams over OBEX (Bluetooth) are not seekable but
2117                  * we expect them to be (we might need to read them
2118                  * several times). So if this is a Bluetooth URI just
2119                  * read the whole file into memory (this is not a fast
2120                  * protocol so we can assume that these files are not
2121                  * going to be very big) */
2122                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2123                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2124                         TnyStream *memstream = tny_camel_mem_stream_new ();
2125                         tny_stream_write_to_stream (vfssstream, memstream);
2126                         g_object_unref (vfssstream);
2127                         result = memstream;
2128                 } else {
2129                         result = vfssstream;
2130                 }
2131         }
2132         
2133         return result;
2134 }
2135
2136 void
2137 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2138 {
2139         
2140         ModestMsgEditWindowPrivate *priv;
2141         GtkWidget *dialog = NULL;
2142         gint response = 0;
2143         GSList *uris = NULL;
2144         GSList *uri_node = NULL;
2145         
2146         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2147         
2148         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2149         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2150         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2151
2152         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2153
2154         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2155                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2156
2157         response = gtk_dialog_run (GTK_DIALOG (dialog));
2158         switch (response) {
2159         case GTK_RESPONSE_OK:
2160                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2161                 break;
2162         default:
2163                 break;
2164         }
2165         gtk_widget_destroy (dialog);
2166
2167         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2168                 const gchar *uri;
2169                 GnomeVFSHandle *handle = NULL;
2170                 GnomeVFSResult result;
2171                 GtkTextIter position;
2172                 GtkTextMark *insert_mark;
2173
2174                 uri = (const gchar *) uri_node->data;
2175                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2176                 if (result == GNOME_VFS_OK) {
2177                         GdkPixbuf *pixbuf;
2178                         GnomeVFSFileInfo *info;
2179                         gchar *filename, *basename, *escaped_filename;
2180                         TnyMimePart *mime_part;
2181                         gchar *content_id;
2182                         const gchar *mime_type = NULL;
2183                         GnomeVFSURI *vfs_uri;
2184                         guint64 stream_size;
2185
2186                         gnome_vfs_close (handle);
2187                         vfs_uri = gnome_vfs_uri_new (uri);
2188
2189                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2190                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2191                         g_free (escaped_filename);
2192                         gnome_vfs_uri_unref (vfs_uri);
2193                         info = gnome_vfs_file_info_new ();
2194
2195                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2196                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2197                             == GNOME_VFS_OK)
2198                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2199
2200                         mime_part = tny_platform_factory_new_mime_part
2201                                 (modest_runtime_get_platform_factory ());
2202                                 
2203                         TnyStream *stream = create_stream_for_uri (uri);
2204
2205                         if (stream == NULL) {
2206
2207                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2208                                 
2209                                 g_object_unref (mime_part);
2210                                 gnome_vfs_file_info_unref (info);
2211                                 continue;
2212                         }
2213
2214                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2215                         
2216                         content_id = g_strdup_printf ("%d", priv->next_cid);
2217                         tny_mime_part_set_content_id (mime_part, content_id);
2218                         g_free (content_id);
2219                         priv->next_cid++;
2220                         
2221                         basename = g_path_get_basename (filename);
2222                         tny_mime_part_set_filename (mime_part, basename);
2223                         g_free (basename);
2224
2225                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2226                         
2227                         if (pixbuf != NULL) {
2228                                 priv->images_size += stream_size;
2229                                 priv->images_count ++;
2230                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2231                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2232                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2233                                 g_object_unref (pixbuf);
2234                         } 
2235
2236                         tny_list_prepend (priv->images, (GObject *) mime_part);
2237                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2238                         g_free (filename);
2239                         g_object_unref (mime_part);
2240                         gnome_vfs_file_info_unref (info);
2241
2242                 }
2243         }
2244
2245
2246 }
2247
2248 static void
2249 on_attach_file_response (GtkDialog *dialog,
2250                          gint       arg1,
2251                          gpointer   user_data)
2252 {
2253         GSList *uris = NULL;
2254         GSList *uri_node;
2255         GnomeVFSFileSize total_size, allowed_size;
2256         ModestMsgEditWindow *window;
2257         ModestMsgEditWindowPrivate *priv;
2258         gint att_num;
2259         guint64 att_size;
2260
2261         switch (arg1) {
2262         case GTK_RESPONSE_OK:
2263                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2264                 break;
2265         default:
2266                 break;
2267         }
2268
2269         window = MODEST_MSG_EDIT_WINDOW (user_data);
2270         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2271
2272         /* allowed size is the maximum size - what's already there */
2273         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2274                                            &att_num, &att_size);
2275         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2276
2277         total_size = 0;
2278         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2279
2280                 const gchar *uri = (const gchar *) uri_node->data;
2281
2282                 total_size += 
2283                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2284
2285                 if (total_size > allowed_size) {
2286                         g_warning ("%s: total size: %u", 
2287                                    __FUNCTION__, (unsigned int)total_size);
2288                         break;
2289                 }
2290                 allowed_size -= total_size;
2291         }
2292         g_slist_foreach (uris, (GFunc) g_free, NULL);
2293         g_slist_free (uris);
2294
2295         gtk_widget_destroy (GTK_WIDGET (dialog));
2296 }
2297
2298 void
2299 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2300 {
2301         GtkWidget *dialog = NULL;
2302         ModestMsgEditWindowPrivate *priv;
2303
2304         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2305
2306         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2307
2308         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2309                 return;
2310
2311         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2312                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2313         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2314         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2315         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2316                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2317
2318         /* Connect to response & show */
2319         g_signal_connect (dialog, "response", 
2320                           G_CALLBACK (on_attach_file_response), window);
2321         gtk_widget_show (dialog);
2322 }
2323
2324
2325 GnomeVFSFileSize
2326 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2327                                         const gchar *uri, 
2328                                         GnomeVFSFileSize allowed_size)
2329
2330 {
2331         GnomeVFSHandle *handle = NULL;
2332         ModestMsgEditWindowPrivate *priv;
2333         GnomeVFSResult result;
2334         GnomeVFSFileSize size = 0;
2335         g_return_val_if_fail (window, 0);
2336         g_return_val_if_fail (uri, 0);
2337
2338         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2339
2340         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2341         if (result == GNOME_VFS_OK) {
2342                 TnyMimePart *mime_part;
2343                 TnyStream *stream;
2344                 const gchar *mime_type = NULL;
2345                 gchar *basename;
2346                 gchar *escaped_filename;
2347                 gchar *filename;
2348                 gchar *content_id;
2349                 GnomeVFSFileInfo *info;
2350                 GnomeVFSURI *vfs_uri;
2351
2352                 gnome_vfs_close (handle);
2353                 vfs_uri = gnome_vfs_uri_new (uri);
2354                 
2355
2356                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2357                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2358                 g_free (escaped_filename);
2359                 gnome_vfs_uri_unref (vfs_uri);
2360
2361                 info = gnome_vfs_file_info_new ();
2362                 
2363                 if (gnome_vfs_get_file_info (uri, 
2364                                              info, 
2365                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2366                     == GNOME_VFS_OK)
2367                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2368                 mime_part = tny_platform_factory_new_mime_part
2369                         (modest_runtime_get_platform_factory ());
2370                 
2371                 /* try to get the attachment's size; this may fail for weird
2372                  * file systems, like obex, upnp... */
2373                 if (allowed_size != 0 &&
2374                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2375                         size = info->size;
2376                         if (size > allowed_size) {
2377                                 modest_platform_information_banner (NULL, NULL, 
2378                                                                     dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2379                                 return 0;
2380                         }
2381                 } else
2382                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2383                 
2384                 stream = create_stream_for_uri (uri);
2385                 
2386                 if (stream == NULL) {
2387
2388                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2389
2390                         g_object_unref (mime_part);
2391                         gnome_vfs_file_info_unref (info);
2392                         return 0;
2393                 }
2394
2395                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2396                 g_object_unref (stream);
2397                 
2398                 content_id = g_strdup_printf ("%d", priv->next_cid);
2399                 tny_mime_part_set_content_id (mime_part, content_id);
2400                 g_free (content_id);
2401                 priv->next_cid++;
2402                 
2403                 basename = g_path_get_basename (filename);
2404                 tny_mime_part_set_filename (mime_part, basename);
2405                 g_free (basename);
2406                 
2407                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2408                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2409                                                         mime_part,
2410                                                         info->size == 0, info->size);
2411                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2412                 gtk_widget_show_all (priv->attachments_caption);
2413                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2414                 g_free (filename);
2415                 g_object_unref (mime_part);
2416                 gnome_vfs_file_info_unref (info);
2417         }
2418
2419         return size;
2420 }
2421
2422 void
2423 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2424                                            TnyList *att_list)
2425 {
2426         ModestMsgEditWindowPrivate *priv;
2427         TnyIterator *iter;
2428
2429         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2430         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2431
2432         if (att_list == NULL) {
2433                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2434         } else {
2435                 g_object_ref (att_list);
2436         }
2437
2438         if (tny_list_get_length (att_list) == 0) {
2439                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2440         } else {
2441                 gboolean dialog_response;
2442                 gchar *message = NULL;
2443                 gchar *filename = NULL;
2444
2445                 if (tny_list_get_length (att_list) == 1) {
2446                         TnyMimePart *part;
2447                         iter = tny_list_create_iterator (att_list);
2448                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2449                         g_object_unref (iter);
2450                         if (TNY_IS_MSG (part)) {
2451                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2452                                 if (header) {
2453                                         filename = tny_header_dup_subject (header);
2454                                         g_object_unref (header);
2455                                 }
2456                                 if (filename == NULL) {
2457                                         filename = g_strdup (_("mail_va_no_subject"));
2458                                 }
2459                         } else {
2460                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2461                         }
2462                         g_object_unref (part);
2463                 } else {
2464                         filename = g_strdup ("");
2465                 }
2466                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2467                                                     "emev_nc_delete_attachments",
2468                                                     tny_list_get_length (att_list)), filename);
2469                 g_free (filename);
2470
2471                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2472                                                                            message);
2473                 g_free (message);
2474
2475                 if (dialog_response != GTK_RESPONSE_OK) {
2476                         g_object_unref (att_list);
2477                         return;
2478                 }
2479
2480                 for (iter = tny_list_create_iterator (att_list);
2481                      !tny_iterator_is_done (iter);
2482                      tny_iterator_next (iter)) {
2483                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2484                         const gchar *att_id;
2485                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2486
2487                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2488                                                                    mime_part);
2489                         if (tny_list_get_length (priv->attachments) == 0)
2490                                 gtk_widget_hide (priv->attachments_caption);
2491                         att_id = tny_mime_part_get_content_id (mime_part);
2492                         if (att_id != NULL)
2493                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2494                                                                  att_id);
2495                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2496                         g_object_unref (mime_part);
2497                 }
2498                 g_object_unref (iter);
2499         }
2500
2501         g_object_unref (att_list);
2502
2503         /* if the last attachment has been removed, focus the Subject: field */
2504         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2505                 gtk_widget_grab_focus (priv->subject_field);
2506 }
2507
2508 static void
2509 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2510                                             gpointer userdata)
2511 {
2512         ModestMsgEditWindowPrivate *priv;
2513         GdkColor *new_color;
2514         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2515         
2516 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2517         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2518 #else 
2519         GdkColor col;
2520         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2521         new_color = &col;
2522 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2523
2524         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2525         
2526         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2527
2528 }
2529
2530 static void
2531 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2532                                     gpointer userdata)
2533 {
2534         ModestMsgEditWindowPrivate *priv;
2535         gint new_size_index;
2536         ModestMsgEditWindow *window;
2537         GtkWidget *label;
2538         
2539         window = MODEST_MSG_EDIT_WINDOW (userdata);
2540         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2541         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2542
2543         if (gtk_check_menu_item_get_active (menu_item)) {
2544                 gchar *markup;
2545                 WPTextBufferFormat format;
2546
2547                 memset (&format, 0, sizeof (format));
2548                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2549
2550                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2551                 
2552                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2553                 format.cs.font_size = TRUE;
2554                 format.cs.text_position = TRUE;
2555                 format.cs.font = TRUE;
2556                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2557 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2558
2559                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2560                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2561                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2562                 
2563                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2564                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2565                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2566                 g_free (markup);
2567         }
2568 }
2569
2570 static void
2571 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2572                                     gpointer userdata)
2573 {
2574         ModestMsgEditWindowPrivate *priv;
2575         gint new_font_index;
2576         ModestMsgEditWindow *window;
2577         GtkWidget *label;
2578         
2579         window = MODEST_MSG_EDIT_WINDOW (userdata);
2580         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2581         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2582
2583         if (gtk_check_menu_item_get_active (menu_item)) {
2584                 gchar *markup;
2585
2586                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2587                 
2588                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2589
2590                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2591                                                    GINT_TO_POINTER(new_font_index)))
2592                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2593                 
2594                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2595                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2596                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2597                 g_free (markup);
2598         }
2599 }
2600
2601 void
2602 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2603                                 gboolean show)
2604 {
2605         ModestMsgEditWindowPrivate *priv = NULL;
2606         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2607
2608         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2609         if (!priv->update_caption_visibility)
2610                 return;
2611
2612         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2613         if (show)
2614                 gtk_widget_show (priv->cc_caption);
2615         else
2616                 gtk_widget_hide (priv->cc_caption);
2617
2618         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2619 }
2620
2621 void
2622 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2623                                  gboolean show)
2624 {
2625         ModestMsgEditWindowPrivate *priv = NULL;
2626         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2627
2628         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2629         if (!priv->update_caption_visibility)
2630                 return;
2631
2632         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2633         if (show)
2634                 gtk_widget_show (priv->bcc_caption);
2635         else
2636                 gtk_widget_hide (priv->bcc_caption);
2637
2638         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2639 }
2640
2641 static void
2642 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2643                                          ModestRecptEditor *editor)
2644 {
2645         ModestMsgEditWindowPrivate *priv;
2646
2647         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2648         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2649         
2650         /* we check for low-mem; in that case, show a warning, and don't allow
2651          * for the addressbook
2652          */
2653         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2654                 return;
2655
2656         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2657
2658         if (editor == NULL) {
2659                 GtkWidget *view_focus;
2660                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2661
2662                 /* This code should be kept in sync with ModestRecptEditor. The
2663                    textview inside the recpt editor is the one that really gets the
2664                    focus. As it's inside a scrolled window, and this one inside the
2665                    hbox recpt editor inherits from, we'll need to go up in the 
2666                    hierarchy to know if the text view is part of the recpt editor
2667                    or if it's a different text entry */
2668
2669                 if (gtk_widget_get_parent (view_focus)) {
2670                         GtkWidget *first_parent;
2671
2672                         first_parent = gtk_widget_get_parent (view_focus);
2673                         if (gtk_widget_get_parent (first_parent) && 
2674                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2675                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2676                         }
2677                 }
2678
2679                 if (editor == NULL)
2680                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2681
2682         }
2683
2684         modest_address_book_select_addresses (editor);
2685
2686 }
2687
2688 void
2689 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2690 {
2691         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2692
2693         modest_msg_edit_window_open_addressbook (window, NULL);
2694 }
2695
2696 static void
2697 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2698                                      gboolean show_toolbar)
2699 {
2700         ModestWindowPrivate *parent_priv;
2701
2702         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2703         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2704
2705         /* We can not just use the code of
2706            modest_msg_edit_window_setup_toolbar because it has a
2707            mixture of both initialization and creation code. */
2708         if (show_toolbar)
2709                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2710         else
2711                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2712 }
2713
2714 void
2715 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2716                                            TnyHeaderFlags priority_flags)
2717 {
2718         ModestMsgEditWindowPrivate *priv;
2719         ModestWindowPrivate *parent_priv;
2720
2721         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2722
2723         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2724         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2725
2726         if (priv->priority_flags != priority_flags) {
2727                 GtkAction *priority_action = NULL;
2728
2729                 priv->priority_flags = priority_flags;
2730
2731                 switch (priority_flags) {
2732                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2733                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2734                                                       MODEST_HEADER_ICON_HIGH, 
2735                                                       HILDON_ICON_SIZE_XSMALL);
2736                         gtk_widget_show (priv->priority_icon);
2737                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2738                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2739                         break;
2740                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2741                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2742                                                       MODEST_HEADER_ICON_LOW,
2743                                                       HILDON_ICON_SIZE_XSMALL);
2744                         gtk_widget_show (priv->priority_icon);
2745                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2746                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2747                         break;
2748                 default:
2749                         gtk_widget_hide (priv->priority_icon);
2750                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2751                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2752                         break;
2753                 }
2754                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2755                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2756         }
2757 }
2758
2759 void
2760 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2761                                         gint file_format)
2762 {
2763         ModestMsgEditWindowPrivate *priv;
2764         ModestWindowPrivate *parent_priv;
2765         gint current_format;
2766
2767         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2768
2769         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2770         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2771
2772         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2773                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2774
2775         if (current_format != file_format) {
2776                 switch (file_format) {
2777                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2778                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2779                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2780                         break;
2781                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2782                 {
2783                         GtkWidget *dialog;
2784                         gint response;
2785                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2786                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2787                         gtk_widget_destroy (dialog);
2788                         if (response == GTK_RESPONSE_OK) {
2789                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2790                         } else {
2791                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2792                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2793                         }
2794                 }
2795                         break;
2796                 }
2797                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2798                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2799                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2800         }
2801 }
2802
2803 void
2804 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2805 {
2806         GtkWidget *dialog;
2807         ModestMsgEditWindowPrivate *priv;
2808         WPTextBufferFormat oldfmt, fmt;
2809         gint old_position = 0;
2810         gint response = 0;
2811         gint position = 0;
2812         gint font_size;
2813         GdkColor *color = NULL;
2814         gboolean bold, bold_set, italic, italic_set;
2815         gboolean underline, underline_set;
2816         gboolean strikethrough, strikethrough_set;
2817         gboolean position_set;
2818         gboolean font_size_set, font_set, color_set;
2819         gchar *font_name;
2820
2821         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2822         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2823         
2824         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2825         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2826                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2827
2828         /* First we get the currently selected font information */
2829         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2830
2831         switch (oldfmt.text_position) {
2832         case TEXT_POSITION_NORMAL:
2833                 old_position = 0;
2834                 break;
2835         case TEXT_POSITION_SUPERSCRIPT:
2836                 old_position = 1;
2837                 break;
2838         default:
2839                 old_position = -1;
2840                 break;
2841         }
2842
2843         g_object_set (G_OBJECT (dialog),
2844                       "bold", oldfmt.bold != FALSE,
2845                       "bold-set", !oldfmt.cs.bold,
2846                       "underline", oldfmt.underline != FALSE,
2847                       "underline-set", !oldfmt.cs.underline,
2848                       "italic", oldfmt.italic != FALSE,
2849                       "italic-set", !oldfmt.cs.italic,
2850                       "strikethrough", oldfmt.strikethrough != FALSE,
2851                       "strikethrough-set", !oldfmt.cs.strikethrough,
2852                       "color", &oldfmt.color,
2853                       "color-set", !oldfmt.cs.color,
2854                       "size", wp_font_size[oldfmt.font_size],
2855                       "size-set", !oldfmt.cs.font_size,
2856                       "position", old_position,
2857                       "position-set", !oldfmt.cs.text_position,
2858                       "family", wp_get_font_name (oldfmt.font),
2859                       "family-set", !oldfmt.cs.font,
2860                       NULL);
2861
2862         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2863                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2864         gtk_widget_show_all (dialog);
2865         priv->font_dialog = dialog;
2866         response = gtk_dialog_run (GTK_DIALOG (dialog));
2867         priv->font_dialog = NULL;
2868         if (response == GTK_RESPONSE_OK) {
2869
2870                 g_object_get( dialog,
2871                               "bold", &bold,
2872                               "bold-set", &bold_set,
2873                               "underline", &underline,
2874                               "underline-set", &underline_set,
2875                               "italic", &italic,
2876                               "italic-set", &italic_set,
2877                               "strikethrough", &strikethrough,
2878                               "strikethrough-set", &strikethrough_set,
2879                               "color", &color,
2880                               "color-set", &color_set,
2881                               "size", &font_size,
2882                               "size-set", &font_size_set,
2883                               "family", &font_name,
2884                               "family-set", &font_set,
2885                               "position", &position,
2886                               "position-set", &position_set,
2887                               NULL );
2888                 
2889         }       
2890
2891         if (response == GTK_RESPONSE_OK) {
2892                 memset(&fmt, 0, sizeof(fmt));
2893                 if (bold_set) {
2894                         fmt.bold = bold;
2895                         fmt.cs.bold = TRUE;
2896                 }
2897                 if (italic_set) {
2898                         fmt.italic = italic;
2899                         fmt.cs.italic = TRUE;
2900                 }
2901                 if (underline_set) {
2902                         fmt.underline = underline;
2903                         fmt.cs.underline = TRUE;
2904                 }
2905                 if (strikethrough_set) {
2906                         fmt.strikethrough = strikethrough;
2907                         fmt.cs.strikethrough = TRUE;
2908                 }
2909                 if (position_set) {
2910                         fmt.text_position =
2911                                 ( position == 0 )
2912                                 ? TEXT_POSITION_NORMAL
2913                                 : ( ( position == 1 )
2914                                     ? TEXT_POSITION_SUPERSCRIPT
2915                                     : TEXT_POSITION_SUBSCRIPT );
2916                         fmt.cs.text_position = TRUE;
2917                         fmt.font_size = oldfmt.font_size;
2918                 }
2919                 if (color_set) {
2920                         fmt.color = *color;
2921                         fmt.cs.color = TRUE;
2922                 }
2923                 if (font_set) {
2924                         fmt.font = wp_get_font_index(font_name,
2925                                                      DEFAULT_FONT);
2926                         fmt.cs.font = TRUE;
2927                 }
2928                 g_free(font_name);
2929                 if (font_size_set) {
2930                         fmt.cs.font_size = TRUE;
2931                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2932                 }
2933                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2934                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2935         }
2936         gtk_widget_destroy (dialog);
2937         
2938         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2939 }
2940
2941 void
2942 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2943 {
2944         ModestMsgEditWindowPrivate *priv;
2945
2946         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2947         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2948         
2949         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2950
2951         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2952         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2953 }
2954
2955 void
2956 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2957 {
2958         ModestMsgEditWindowPrivate *priv;
2959
2960         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2961         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2962         
2963         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2964
2965         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2966         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2967
2968 }
2969
2970 static void  
2971 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2972 {
2973         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2974
2975         priv->can_undo = can_undo;
2976 }
2977
2978 static void  
2979 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2980 {
2981         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982
2983         priv->can_redo = can_redo;
2984 }
2985
2986 gboolean            
2987 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2988 {
2989         ModestMsgEditWindowPrivate *priv;
2990         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2991         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2992
2993         return priv->can_undo;
2994 }
2995
2996 gboolean            
2997 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2998 {
2999         ModestMsgEditWindowPrivate *priv;
3000         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3001         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3002
3003         return priv->can_redo;
3004 }
3005
3006
3007 static void
3008 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3009 {
3010         GtkTextIter iter;
3011         GtkTextIter match_start, match_end;
3012
3013         if (image_id == NULL)
3014                 return;
3015
3016         gtk_text_buffer_get_start_iter (buffer, &iter);
3017
3018         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3019                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3020                 GSList *node;
3021                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3022                         GtkTextTag *tag = (GtkTextTag *) node->data;
3023                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3024                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3025                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3026                                         gint offset;
3027                                         offset = gtk_text_iter_get_offset (&match_start);
3028                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3029                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3030                                 }
3031                         }
3032                 }
3033                 gtk_text_iter_forward_char (&iter);
3034         }
3035 }
3036
3037 gboolean
3038 message_is_empty (ModestMsgEditWindow *window)
3039 {
3040         ModestMsgEditWindowPrivate *priv = NULL;
3041
3042         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3043         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3044
3045         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3046          * so we can ignore markup.
3047          */
3048         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3049         gint count = 0;
3050         if (buf)
3051                 count = gtk_text_buffer_get_char_count (buf);
3052
3053         return count == 0;
3054 }
3055
3056 static gboolean
3057 msg_body_focus (GtkWidget *focus,
3058                 GdkEventFocus *event,
3059                 gpointer userdata)
3060 {
3061         
3062         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3063         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3064         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3065         return FALSE;
3066 }
3067
3068 static void
3069 recpt_field_changed (GtkTextBuffer *buffer,
3070                   ModestMsgEditWindow *editor)
3071 {
3072         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3073         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3074 }
3075
3076 static void
3077 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3078 {
3079         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3080         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3081 }
3082
3083 void
3084 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3085                                      gboolean modified)
3086 {
3087         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3088         GtkTextBuffer *buffer;
3089
3090         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3091         gtk_text_buffer_set_modified (buffer, modified);
3092         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3093         gtk_text_buffer_set_modified (buffer, modified);
3094         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3095         gtk_text_buffer_set_modified (buffer, modified);
3096         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3097 }
3098
3099 gboolean
3100 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3101 {
3102         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3103         const char *account_name;
3104         GtkTextBuffer *buffer;
3105
3106         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3107         if (gtk_text_buffer_get_modified (buffer))
3108                 return TRUE;
3109         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3110         if (gtk_text_buffer_get_modified (buffer))
3111                 return TRUE;
3112         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3113         if (gtk_text_buffer_get_modified (buffer))
3114                 return TRUE;
3115         if (gtk_text_buffer_get_modified (priv->text_buffer))
3116                 return TRUE;
3117         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3118         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3119                 return TRUE;
3120         }
3121
3122         return FALSE;
3123 }
3124
3125
3126
3127
3128 gboolean
3129 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3130 {
3131         ModestMsgEditWindowPrivate *priv = NULL;
3132         
3133         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3134         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3135
3136         /* check if there's no recipient added */
3137         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3138             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3139             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3140                 /* no recipient contents, then select contacts */
3141                 modest_msg_edit_window_open_addressbook (window, NULL);
3142                 return FALSE;
3143         }
3144
3145         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3146                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3147                 return FALSE;
3148         }
3149         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3150                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3151                 return FALSE;
3152         }
3153         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3154                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3155                 return FALSE;
3156         }
3157
3158         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3159             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3160                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3161
3162         return TRUE;
3163
3164 }
3165
3166 static void
3167 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3168                                                ModestMsgEditWindow *window)
3169 {
3170         modest_msg_edit_window_offer_attach_file (window);
3171 }
3172
3173 const gchar *
3174 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3175 {
3176         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3177
3178         return priv->clipboard_text;
3179 }
3180
3181 static void
3182 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3183                                                GdkEvent *event,
3184                                                ModestMsgEditWindow *window)
3185 {
3186         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3187         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3188         gchar *text = NULL;
3189         if (!GTK_WIDGET_VISIBLE (window))
3190                 return;
3191
3192         g_object_ref (window);
3193         text = gtk_clipboard_wait_for_text (selection_clipboard);
3194
3195         if (priv->clipboard_text != NULL) {
3196                 g_free (priv->clipboard_text);
3197         }
3198         priv->clipboard_text = text;
3199
3200         if (GTK_WIDGET_VISIBLE (window)) {
3201                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3202         }
3203         g_object_unref (window);
3204 }
3205
3206 static gboolean clipboard_owner_change_idle (gpointer userdata)
3207 {
3208         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3209         ModestMsgEditWindowPrivate *priv;
3210
3211         gdk_threads_enter ();
3212         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3213         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3214
3215         priv->clipboard_owner_idle = 0;
3216         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3217         gdk_threads_leave ();
3218
3219         return FALSE;
3220 }
3221
3222 static void
3223 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3224 {
3225         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226         if (priv->clipboard_owner_idle == 0) {
3227                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3228         }
3229 }
3230
3231 static void 
3232 subject_field_move_cursor (GtkEntry *entry,
3233                            GtkMovementStep step,
3234                            gint a1,
3235                            gboolean a2,
3236                            gpointer window)
3237 {
3238         if (!GTK_WIDGET_VISIBLE (window))
3239                 return;
3240
3241         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3242 }
3243
3244 static void 
3245 update_window_title (ModestMsgEditWindow *window)
3246 {
3247         ModestMsgEditWindowPrivate *priv = NULL;
3248         const gchar *subject;
3249
3250         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3251         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3252         if (subject == NULL || subject[0] == '\0')
3253                 subject = _("mail_va_new_email");
3254
3255         gtk_window_set_title (GTK_WINDOW (window), subject);
3256
3257 }
3258
3259 static void  
3260 subject_field_changed (GtkEditable *editable, 
3261                        ModestMsgEditWindow *window)
3262 {
3263         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3264         update_window_title (window);
3265         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3266         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3267         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3268 }
3269
3270 static void  
3271 subject_field_insert_text (GtkEditable *editable, 
3272                            gchar *new_text,
3273                            gint new_text_length,
3274                            gint *position,
3275                            ModestMsgEditWindow *window)
3276 {
3277         GString *result = g_string_new ("");
3278         gchar *current;
3279         gint result_len = 0;
3280         const gchar *entry_text = NULL;
3281         gint old_length;
3282
3283         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3284         old_length = g_utf8_strlen (entry_text, -1);
3285
3286         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3287                 gunichar c = g_utf8_get_char_validated (current, 8);
3288                 /* Invalid unichar, stop */
3289                 if (c == -1)
3290                         break;
3291                 /* a bullet */
3292                 if (c == 0x2022)
3293                         continue;
3294                 result = g_string_append_unichar (result, c);
3295                 result_len++;
3296         }
3297
3298         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3299                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3300                 if (result_len > 0)
3301                 {
3302                         /* Prevent endless recursion */
3303                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3304                         g_signal_emit_by_name (editable, "insert-text", 
3305                                                (gpointer) result->str, (gpointer) result->len,
3306                                                (gpointer) position, (gpointer) window);
3307                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3308                 }
3309         }
3310
3311         if (result_len + old_length > 1000) {
3312                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3313                                                 dgettext("hildon-common-strings",
3314                                                          "ckdg_ib_maximum_characters_reached"));
3315         }
3316         g_string_free (result, TRUE);
3317 }
3318
3319 void
3320 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3321                                             gboolean show)
3322 {
3323         ModestMsgEditWindowPrivate *priv = NULL;
3324
3325         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3326         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3327
3328         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3329
3330         if (show) {
3331                 gtk_widget_show_all (priv->find_toolbar);
3332                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3333         } else {
3334                 gtk_widget_hide_all (priv->find_toolbar);
3335                 gtk_widget_grab_focus (priv->msg_body);
3336         }
3337 }
3338
3339 static gboolean 
3340 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3341                                           const gchar *str,
3342                                           GtkTextIter *match_start,
3343                                           GtkTextIter *match_end)
3344 {
3345         GtkTextIter end_iter;
3346         gchar *str_casefold;
3347         gint str_chars_n;
3348         gchar *range_text;
3349         gchar *range_casefold;
3350         gint offset;
3351         gint range_chars_n;
3352         gboolean result = FALSE;
3353
3354         if (str == NULL)
3355                 return TRUE;
3356         
3357         /* get end iter */
3358         end_iter = *iter;
3359         gtk_text_iter_forward_to_end (&end_iter);
3360
3361         str_casefold = g_utf8_casefold (str, -1);
3362         str_chars_n = strlen (str);
3363
3364         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3365         range_casefold = g_utf8_casefold (range_text, -1);
3366         range_chars_n = strlen (range_casefold);
3367
3368         if (range_chars_n < str_chars_n) {
3369                 g_free (str_casefold);
3370                 g_free (range_text);
3371                 g_free (range_casefold);
3372                 return FALSE;
3373         }
3374
3375         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3376                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3377                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3378                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3379                         result = TRUE;
3380                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3381                                                       match_start, match_end, NULL);
3382                         g_free (found_text);
3383                 }
3384                 g_free (range_subtext);
3385                 if (result)
3386                         break;
3387         }
3388         g_free (str_casefold);
3389         g_free (range_text);
3390         g_free (range_casefold);
3391
3392         return result;
3393 }
3394
3395
3396 static void 
3397 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3398                                             ModestMsgEditWindow *window)
3399 {
3400         gchar *current_search = NULL;
3401         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3402         gboolean result;
3403         GtkTextIter selection_start, selection_end;
3404         GtkTextIter match_start, match_end;
3405         gboolean continue_search = FALSE;
3406
3407         if (message_is_empty (window)) {
3408                 g_free (priv->last_search);
3409                 priv->last_search = NULL;
3410                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3411                 return;
3412         }
3413
3414         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3415         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3416                 g_free (current_search);
3417                 g_free (priv->last_search);
3418                 priv->last_search = NULL;
3419                 /* Information banner about empty search */
3420                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3421                 return;
3422         }
3423
3424         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3425                 continue_search = TRUE;
3426         } else {
3427                 g_free (priv->last_search);
3428                 priv->last_search = g_strdup (current_search);
3429         }
3430
3431         if (continue_search) {
3432                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3433                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3434                                                                    &match_start, &match_end);
3435                 if (!result)
3436                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3437         } else {
3438                 GtkTextIter buffer_start;
3439                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3440                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3441                                                                    &match_start, &match_end);
3442                 if (!result)
3443                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3444         }
3445
3446         /* Mark as selected the string found in search */
3447         if (result) {
3448                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3449                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3450                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3451         } else {
3452                 g_free (priv->last_search);
3453                 priv->last_search = NULL;
3454         }
3455         g_free (current_search);
3456 }
3457
3458 gboolean 
3459 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3460 {
3461         ModestMsgEditWindowPrivate *priv;
3462
3463         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3464         return priv->sent;
3465 }
3466
3467 void 
3468 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3469                                  gboolean sent)
3470 {
3471         ModestMsgEditWindowPrivate *priv;
3472
3473         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3474         priv->sent = sent;
3475 }
3476
3477 static void
3478 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3479                                           ModestMsgEditWindow *window)
3480 {
3481         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3482 }
3483
3484 void
3485 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3486                                   TnyMsg *draft)
3487 {
3488         ModestMsgEditWindowPrivate *priv;
3489         TnyHeader *header = NULL;
3490
3491         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3492         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3493
3494         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3495         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3496
3497         if (priv->draft_msg != NULL) {
3498                 g_object_unref (priv->draft_msg);
3499         }
3500
3501         if (draft != NULL) {
3502                 g_object_ref (draft);
3503                 header = tny_msg_get_header (draft);
3504                 if (priv->msg_uid) {
3505                         g_free (priv->msg_uid);
3506                         priv->msg_uid = NULL;
3507                 }
3508                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3509                 if (GTK_WIDGET_REALIZED (window)) {
3510                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3511                                 gtk_widget_destroy (GTK_WIDGET (window));
3512                                 return;
3513                         }
3514                 }
3515         }
3516
3517         priv->draft_msg = draft;
3518 }
3519
3520 static void  
3521 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3522                        GtkTextIter *start, GtkTextIter *end,
3523                        gpointer userdata)
3524 {
3525         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3526         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3527         gchar *tag_name;
3528
3529         if (tag == NULL) return;
3530         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3531         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3532                 replace_with_images (window, priv->images);
3533         }
3534 }
3535
3536 void                    
3537 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3538                                  TnyMimePart *part)
3539 {
3540         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3541
3542         g_return_if_fail (TNY_IS_MIME_PART (part));
3543         tny_list_prepend (priv->attachments, (GObject *) part);
3544         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3545         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3546         gtk_widget_show_all (priv->attachments_caption);
3547         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3548 }
3549
3550 const gchar*    
3551 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3552 {
3553         ModestMsgEditWindowPrivate *priv;
3554
3555         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3556         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3557
3558         return priv->msg_uid;
3559 }
3560
3561 GtkWidget *
3562 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3563                                          ModestMsgEditWindowWidgetType widget_type)
3564 {
3565         ModestMsgEditWindowPrivate *priv;
3566
3567         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3568         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3569
3570         switch (widget_type) {
3571         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3572                 return priv->msg_body;
3573                 break;
3574         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3575                 return priv->to_field;
3576                 break;
3577         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3578                 return priv->cc_field;
3579                 break;
3580         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3581                 return priv->bcc_field;
3582                 break;
3583         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3584                 return priv->subject_field;
3585                 break;
3586         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3587                 return priv->attachments_view;
3588                 break;
3589         default:
3590                 return NULL;
3591         }
3592 }
3593
3594 static void 
3595 remove_tags (WPTextBuffer *buffer)
3596 {
3597         GtkTextIter start, end;
3598
3599         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3600         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3601
3602         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3603 }
3604
3605 static void
3606 on_account_removed (TnyAccountStore *account_store, 
3607                     TnyAccount *account,
3608                     gpointer user_data)
3609 {
3610         /* Do nothing if it's a store account, because we use the
3611            transport to send the messages */
3612         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3613                 const gchar *parent_acc = NULL;
3614                 const gchar *our_acc = NULL;
3615
3616                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3617                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3618                 /* Close this window if I'm showing a message of the removed account */
3619                 if (strcmp (parent_acc, our_acc) == 0)
3620                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3621         }
3622 }
3623
3624 typedef struct _MessageSettingsHelper {
3625         ModestMsgEditWindow *window;
3626         GSList *priority_group;
3627         GSList *format_group;
3628 } MessageSettingsHelper;
3629
3630 static void
3631 on_priority_toggle (GtkToggleButton *button, 
3632                     MessageSettingsHelper *helper)
3633 {
3634         GSList *node;
3635         ModestMsgEditWindowPrivate *priv;
3636
3637         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3638         if (gtk_toggle_button_get_active (button)) {
3639
3640                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3641                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3642                         if ((node_button != button) &&
3643                             gtk_toggle_button_get_active (node_button)) {
3644                                 gtk_toggle_button_set_active (node_button, FALSE);
3645                         }
3646                 }
3647                 if (priv->priority_flags != (TnyHeaderFlags) g_object_get_data (G_OBJECT (button), "priority"))
3648                         modest_msg_edit_window_set_priority_flags (helper->window,
3649                                                                    (TnyHeaderFlags) 
3650                                                                    g_object_get_data (G_OBJECT (button), 
3651                                                                                       "priority"));
3652                 
3653         } else {
3654                 gboolean found = FALSE;
3655                 /* If no one is active, activate it again */
3656                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3657                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3658                         if (gtk_toggle_button_get_active (node_button)) {
3659                                 found = TRUE;
3660                                 break;
3661                         }
3662                 }
3663                 if (!found) {
3664                         gtk_toggle_button_set_active (button, TRUE);
3665                 }
3666         }
3667 }
3668
3669 static void
3670 on_format_toggle (GtkToggleButton *button,
3671                   MessageSettingsHelper *helper)
3672 {
3673         GSList *node;
3674         ModestMsgEditWindowPrivate *priv;
3675         ModestMsgEditFormat old_format;
3676
3677         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3678         old_format = modest_msg_edit_window_get_format (helper->window);
3679         if (gtk_toggle_button_get_active (button)) {
3680
3681                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3682                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3683                         if ((node_button != button) &&
3684                             gtk_toggle_button_get_active (node_button)) {
3685                                 gtk_toggle_button_set_active (node_button, FALSE);
3686                         }
3687                 }
3688                 if (old_format != (ModestMsgEditFormat) g_object_get_data (G_OBJECT (button), "format")) {
3689                         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (helper->window), 
3690                                                                 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "file-format")));
3691                 }
3692                 
3693         } else {
3694                 gboolean found = FALSE;
3695                 /* If no one is active, activate it again */
3696                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3697                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3698                         if (gtk_toggle_button_get_active (node_button)) {
3699                                 found = TRUE;
3700                                 break;
3701                         }
3702                 }
3703                 if (!found) {
3704                         gtk_toggle_button_set_active (button, TRUE);
3705                 }
3706         }
3707
3708 }
3709
3710 static void
3711 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3712 {
3713         GtkWidget *dialog;
3714         GtkWidget *vbox;
3715         GtkWidget *priority_hbox;
3716         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3717         GtkWidget *captioned;
3718         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3719         GtkWidget *format_hbox;
3720         GtkWidget *html_toggle, *text_toggle;
3721         ModestMsgEditWindowPrivate *priv;
3722         MessageSettingsHelper helper = {0,};
3723
3724         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3725         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3726         helper.window = window;
3727         helper.priority_group = NULL;
3728
3729         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3730         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3731
3732         dialog = gtk_dialog_new ();
3733         vbox = gtk_vbox_new (FALSE, 0);
3734         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
3735         gtk_widget_show (vbox);
3736
3737         /* Priority toggles */
3738         priority_hbox = gtk_hbox_new (TRUE, 0);
3739         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3740         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3741         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3742         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3743         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3744         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3745         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3746         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3747         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3748         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3749         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3750         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3751         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3752         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3753         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3754         gtk_widget_show_all (priority_hbox);
3755         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3756                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3757         gtk_widget_show (captioned);
3758         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3759
3760         /* format toggles */
3761         format_hbox = gtk_hbox_new (TRUE, 0);
3762         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3763         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3764         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3765         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3766         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3767         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3768         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3769         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3770         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3771         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3772         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3773         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3774         gtk_widget_show_all (format_hbox);
3775         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3776                                                          _("mcen_me_editor_format"), FALSE, format_hbox);
3777         gtk_widget_show (captioned);
3778         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3779
3780
3781         g_object_unref (title_sizegroup);
3782         g_object_unref (value_sizegroup);
3783         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_me_message_settings"));
3784
3785         /* Set current values */
3786         switch (priv->priority_flags) {
3787         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3788                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3789                 break;
3790         case TNY_HEADER_FLAG_LOW_PRIORITY:
3791                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3792                 break;
3793         default:
3794                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3795                 break;
3796         }
3797
3798         switch (modest_msg_edit_window_get_format (window)) {
3799         case MODEST_MSG_EDIT_FORMAT_TEXT:
3800                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3801                 break;
3802         case MODEST_MSG_EDIT_FORMAT_HTML:
3803         default:
3804                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3805                 break;
3806         }
3807
3808         /* Signal connects */
3809         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3810         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3811         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3812         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3813         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3814         
3815         gtk_dialog_run (GTK_DIALOG (dialog));
3816         
3817         /* Read new values */
3818         
3819         gtk_widget_destroy (dialog);
3820         g_slist_free (helper.priority_group);
3821         
3822 }
3823
3824 static void on_message_settings (GtkAction *action,
3825                                  ModestMsgEditWindow *window)
3826 {
3827         modest_msg_edit_window_show_msg_settings_dialog (window);
3828 }
3829
3830 static void
3831 on_cc_button_toggled (HildonCheckButton *button,
3832                       ModestMsgEditWindow *window)
3833 {
3834         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3835
3836         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3837                                         hildon_check_button_get_active (button));
3838 }
3839
3840 static void
3841 on_bcc_button_toggled (HildonCheckButton *button,
3842                       ModestMsgEditWindow *window)
3843 {
3844         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3845
3846         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3847                                         hildon_check_button_get_active (button));
3848 }
3849
3850 static void 
3851 setup_menu (ModestMsgEditWindow *self)
3852 {
3853         ModestMsgEditWindowPrivate *priv = NULL;
3854
3855         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3856
3857         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3858
3859         /* Settings menu buttons */
3860         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3861                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3862                                            NULL);
3863         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3864                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3865                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3866
3867         priv->cc_button = hildon_check_button_new (0);
3868         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3869         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3870                                         FALSE);
3871         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3872                                                   NULL);
3873         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3874                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3875         priv->bcc_button = hildon_check_button_new (0);
3876         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3877         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3878                                         FALSE);
3879         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3880                                                   NULL);
3881         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3882                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3883
3884         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3885                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3886                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3887         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3888                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3889                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3890         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
3891                                            APP_MENU_CALLBACK (on_message_settings),
3892                                            NULL);
3893         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
3894                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
3895                                            NULL);
3896 }
3897