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