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