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