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