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