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