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