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