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