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