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