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