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