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