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