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