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