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