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