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