Added the function that quotes emails
[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 #ifdef MODEST_HAVE_HILDON0_WIDGETS
74 #include <hildon-widgets/hildon-color-chooser.h>
75 #endif
76 #include "widgets/modest-msg-edit-window-ui.h"
77 #ifdef MODEST_HAVE_HILDON0_WIDGETS
78 #include <libgnomevfs/gnome-vfs-mime-utils.h>
79 #else
80 #include <libgnomevfs/gnome-vfs-mime.h>
81 #endif
82 #include <modest-utils.h>
83 #include "modest-maemo-utils.h"
84 #include <modest-ui-constants.h>
85
86
87 #define DEFAULT_FONT_SIZE 3
88 #define DEFAULT_FONT 2
89 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
90 #define DEFAULT_MAIN_VBOX_SPACING 6
91 #define SUBJECT_MAX_LENGTH 1000
92 #define IMAGE_MAX_WIDTH 560
93 #define DEFAULT_FONT_SCALE 1.5
94 #define ATTACHMENT_BUTTON_WIDTH 118
95 #define MAX_FROM_VALUE 36
96 #define MAX_BODY_LENGTH 128*1024
97 #define MAX_BODY_LINES 2048
98
99 static gboolean is_wp_text_buffer_started = FALSE;
100
101 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
102 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
103 static void  modest_msg_edit_window_finalize     (GObject *obj);
104
105 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
106 static void  body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
107 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
108
109 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
110 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
111 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
112 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
113                                     GtkTextIter *start, GtkTextIter *end,
114                                     gpointer userdata);
115 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
116 static void  body_insert_text (GtkTextBuffer *buffer, 
117                                       GtkTextIter *location,
118                                       gchar *text,
119                                       gint len,
120                                       ModestMsgEditWindow *window);
121 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
122 static void  subject_field_insert_text (GtkEditable *editable, 
123                                         gchar *new_text,
124                                         gint new_text_length,
125                                         gint *position,
126                                         ModestMsgEditWindow *window);
127 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
128                                                          gpointer userdata);
129 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
130
131 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
132                                                      ModestRecptEditor *editor);
133 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
134                                                            ModestMsgEditWindow *window);
135
136 /* ModestWindow methods implementation */
137 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
138 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
139                                                    gboolean show_toolbar);
140 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
141                                                            GdkEvent *event,
142                                                            ModestMsgEditWindow *window);
143 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window);
144 static void subject_field_move_cursor (GtkEntry *entry,
145                                        GtkMovementStep step,
146                                        gint a1,
147                                        gboolean a2,
148                                        gpointer userdata);
149 static void update_window_title (ModestMsgEditWindow *window);
150
151 /* Find toolbar */
152 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
153                                                         ModestMsgEditWindow *window);
154 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
155                                                        ModestMsgEditWindow *window);
156 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
157                                                           const gchar *str,
158                                                           GtkTextIter *match_start,
159                                                           GtkTextIter *match_end);
160
161 static void remove_tags (WPTextBuffer *buffer);
162
163 static void on_account_removed (TnyAccountStore *account_store, 
164                                 TnyAccount *account,
165                                 gpointer user_data);
166
167 static void init_window (ModestMsgEditWindow *obj);
168
169 gboolean scroll_drag_timeout (gpointer userdata);
170 static void correct_scroll (ModestMsgEditWindow *w);
171 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
172 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
173                                          ModestMsgEditWindow *userdata);
174 static void text_buffer_mark_set (GtkTextBuffer *buffer,
175                                   GtkTextIter *iter,
176                                   GtkTextMark *mark,
177                                   ModestMsgEditWindow *userdata);
178 static void on_message_settings (GtkAction *action,
179                                  ModestMsgEditWindow *window);
180 static void setup_menu (ModestMsgEditWindow *self);
181
182 static void from_field_changed (HildonPickerButton *button,
183                                 ModestMsgEditWindow *self);
184 static void font_size_clicked (GtkToolButton *button,
185                                ModestMsgEditWindow *window);
186 static void font_face_clicked (GtkToolButton *button,
187                                ModestMsgEditWindow *window);
188 static void update_signature (ModestMsgEditWindow *self,
189                               const gchar *old_account, 
190                               const gchar *new_account);
191 static void update_branding (ModestMsgEditWindow *self,
192                              const gchar *new_account);
193 static GtkWidget *_create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
194                                            const gchar *label, GtkWidget *control);
195 static void max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref);
196 static void DEBUG_BUFFER (WPTextBuffer *buffer)
197 {
198 #ifdef DEBUG
199         GtkTextIter iter;
200         g_debug ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
201
202         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
203         while (!gtk_text_iter_is_end (&iter)) {
204                 GString *output = g_string_new ("");
205                 GSList *toggled_tags;
206                 GSList *node;
207
208                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
209                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
210                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
211                         GtkTextTag *tag = (GtkTextTag *) node->data;
212                         const gchar *name;
213                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
214                         output = g_string_append (output, name);
215                         g_string_append (output, " ");
216                 }
217                 output = g_string_append (output, "] OPENED [ ");
218                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
219                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
220                         GtkTextTag *tag = (GtkTextTag *) node->data;
221                         const gchar *name;
222                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
223                         output = g_string_append (output, name);
224                         g_string_append (output, " ");
225                 }
226                 output = g_string_append (output, "]\n");
227                 g_debug ("%s", output->str);
228                 g_string_free (output, TRUE);
229                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
230         }
231         g_debug ("END BUFFER");
232 #endif
233 }
234
235 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
236         { "MessageSettings", NULL, N_("mcen_me_message_settings"), NULL, NULL, G_CALLBACK (on_message_settings)},
237 };
238
239
240 /* static gboolean */
241 /* on_key_pressed (GtkWidget *self, */
242 /*              GdkEventKey *event, */
243 /*              gpointer user_data); */
244
245 /* list my signals */
246 enum {
247         /* MY_SIGNAL_1, */
248         /* MY_SIGNAL_2, */
249         LAST_SIGNAL
250 };
251
252 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
253 struct _ModestMsgEditWindowPrivate {
254         GtkWidget   *msg_body;
255         GtkWidget   *header_box;
256         
257         ModestPairList *from_field_protos;
258         GtkWidget   *from_field;
259         gchar       *last_from_account;
260         gchar       *original_account_name;
261
262         gchar       *references;
263         gchar       *in_reply_to;
264
265         gchar       *original_mailbox;
266         
267         GtkWidget   *to_field;
268         GtkWidget   *cc_field;
269         GtkWidget   *bcc_field;
270         GtkWidget   *subject_field;
271         GtkWidget   *attachments_view;
272         GtkWidget   *priority_icon;
273         GtkWidget   *subject_box;
274         GtkWidget   *send_button;
275
276         GtkWidget   *cc_caption;
277         GtkWidget   *bcc_caption;
278         gboolean     update_caption_visibility;
279         GtkWidget   *attachments_caption;
280
281         GtkTextBuffer *text_buffer;
282
283         GtkWidget   *font_size_toolitem;
284         GtkWidget   *font_face_toolitem;
285         GtkWidget   *font_color_button;
286         GtkWidget   *font_color_toolitem;
287         GSList      *font_items_group;
288         GtkTreeModel *faces_model;
289         gint         current_face_index;
290         GtkWidget   *font_tool_button_label;
291         GtkTreeModel *sizes_model;
292         gint         current_size_index;
293         GtkWidget   *size_tool_button_label;
294
295         GtkWidget   *find_toolbar;
296         gchar       *last_search;
297
298         GtkWidget   *font_dialog;
299
300         GtkWidget   *pannable;
301         guint        correct_scroll_idle;
302         guint        scroll_drag_timeout_id;
303         gdouble      last_upper;
304
305         gint next_cid;
306         TnyList *attachments;
307         TnyList *images;
308         guint64 images_size;
309         gint images_count;
310
311         TnyHeaderFlags priority_flags;
312
313         gboolean    can_undo, can_redo;
314         gulong      clipboard_change_handler_id;
315         gulong      default_clipboard_change_handler_id;
316         gulong      account_removed_handler_id;
317         guint       clipboard_owner_idle;
318         gchar       *clipboard_text;
319
320         TnyMsg      *draft_msg;
321         TnyMsg      *outbox_msg;
322         gchar       *msg_uid;
323
324         gboolean    sent;
325
326         GtkWidget   *app_menu;
327         GtkWidget   *cc_button;
328         GtkWidget   *bcc_button;
329
330         GtkWidget   *max_chars_banner;
331
332         GtkWidget   *brand_icon;
333         GtkWidget   *brand_label;
334         GtkWidget   *brand_container;
335 };
336
337 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
338                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
339                                                     ModestMsgEditWindowPrivate))
340 /* globals */
341 static GtkWindowClass *parent_class = NULL;
342
343 /* uncomment the following if you have defined any signals */
344 /* static guint signals[LAST_SIGNAL] = {0}; */
345
346 GType
347 modest_msg_edit_window_get_type (void)
348 {
349         static GType my_type = 0;
350         if (!my_type) {
351                 static const GTypeInfo my_info = {
352                         sizeof(ModestMsgEditWindowClass),
353                         NULL,           /* base init */
354                         NULL,           /* base finalize */
355                         (GClassInitFunc) modest_msg_edit_window_class_init,
356                         NULL,           /* class finalize */
357                         NULL,           /* class data */
358                         sizeof(ModestMsgEditWindow),
359                         1,              /* n_preallocs */
360                         (GInstanceInitFunc) modest_msg_edit_window_init,
361                         NULL
362                 };
363                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
364                                                   "ModestMsgEditWindow",
365                                                   &my_info, 0);
366
367         }
368         return my_type;
369 }
370
371 static void
372 save_state (ModestWindow *self)
373 {
374         modest_widget_memory_save (modest_runtime_get_conf(),
375                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
376 }
377
378
379 static void
380 restore_settings (ModestMsgEditWindow *self)
381 {
382         ModestConf *conf = NULL;
383
384         conf = modest_runtime_get_conf ();
385
386         /* Dim at start clipboard actions */
387         modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
388 }
389
390
391 static void
392 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
393 {
394         GObjectClass *gobject_class;
395         ModestWindowClass *modest_window_class;
396         gobject_class = (GObjectClass*) klass;
397         modest_window_class = (ModestWindowClass*) klass;
398
399         parent_class            = g_type_class_peek_parent (klass);
400         gobject_class->finalize = modest_msg_edit_window_finalize;
401
402         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
403         modest_window_class->save_state_func = save_state;
404         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
405
406         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
407 }
408
409 static void
410 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
411 {
412         ModestMsgEditWindowPrivate *priv;
413         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
414
415         priv->msg_body      = NULL;
416         priv->from_field    = NULL;
417         priv->to_field      = NULL;
418         priv->cc_field      = NULL;
419         priv->bcc_field     = NULL;
420         priv->subject_field = NULL;
421         priv->attachments   = TNY_LIST (tny_simple_list_new ());
422         priv->images        = TNY_LIST (tny_simple_list_new ());
423         priv->images_size   = 0;
424         priv->images_count  = 0;
425         priv->next_cid      = 0;
426
427         priv->cc_caption    = NULL;
428         priv->bcc_caption    = NULL;
429         priv->update_caption_visibility = FALSE;
430
431         priv->priority_flags = 0;
432
433         priv->find_toolbar = NULL;
434         priv->last_search = NULL;
435
436         priv->draft_msg = NULL;
437         priv->outbox_msg = NULL;
438         priv->msg_uid = NULL;
439
440         priv->can_undo = FALSE;
441         priv->can_redo = FALSE;
442         priv->clipboard_change_handler_id = 0;
443         priv->default_clipboard_change_handler_id = 0;
444         priv->account_removed_handler_id = 0;
445         priv->clipboard_owner_idle = 0;
446         priv->clipboard_text = NULL;
447         priv->sent = FALSE;
448
449         priv->scroll_drag_timeout_id = 0;
450         priv->correct_scroll_idle = 0;
451         priv->last_upper = 0.0;
452
453         priv->font_dialog = NULL;
454         priv->app_menu = NULL;
455
456         priv->references = NULL;
457         priv->in_reply_to = NULL;
458         priv->max_chars_banner = NULL;
459
460         if (!is_wp_text_buffer_started) {
461                 is_wp_text_buffer_started = TRUE;
462                 wp_text_buffer_library_init ();
463         }
464
465         init_window (obj);
466         
467         hildon_program_add_window (hildon_program_get_instance(),
468                                    HILDON_WINDOW(obj));
469 }
470
471 static gchar *
472 multimailbox_get_default_mailbox (const gchar *account_name)
473 {
474         gchar *transport_account;
475         gchar *result = NULL;
476
477         transport_account = modest_account_mgr_get_server_account_name (modest_runtime_get_account_mgr (),
478                                                                         account_name,
479                                                                         TNY_ACCOUNT_TYPE_TRANSPORT);
480         if (transport_account) {
481                 gchar *proto;
482                 ModestProtocolRegistry *registry;
483
484                 registry = modest_runtime_get_protocol_registry ();
485
486                 proto = modest_account_mgr_get_string (modest_runtime_get_account_mgr (), transport_account, 
487                                                        MODEST_ACCOUNT_PROTO, TRUE);
488                 if (proto != NULL) {
489                         ModestProtocol *protocol = 
490                                 modest_protocol_registry_get_protocol_by_name (registry,
491                                                                                MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS,
492                                                                                proto);
493                         if (MODEST_ACCOUNT_PROTOCOL (protocol)) {
494                                 ModestPairList *pair_list;
495
496                                 pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
497                                                                                    account_name);
498                                 if (pair_list) {
499                                         ModestPair *pair = (ModestPair *) pair_list->data;
500                                         result = g_strdup ((const gchar *) pair->first);
501                                         modest_pair_list_free (pair_list);
502                                 }
503                         }
504                         
505                 }
506         }
507
508         return result;
509 }
510
511 /** 
512  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
513  */
514 static ModestPairList*
515 get_transports (void)
516 {
517         GSList *transports = NULL;
518         
519         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
520         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
521                                                              TRUE /* only enabled accounts. */); 
522                                                 
523         GSList *cursor = accounts;
524         while (cursor) {
525                 gchar *account_name = cursor->data;
526                 if (account_name) {
527
528                         gchar *transport_account;
529                         gboolean multi_mailbox = FALSE;
530                         ModestProtocol *protocol = NULL;
531
532                         if (modest_account_mgr_account_is_multimailbox (account_mgr, account_name, &protocol)) {
533
534                                 transport_account = modest_account_mgr_get_server_account_name 
535                                         (modest_runtime_get_account_mgr (),
536                                          account_name,
537                                          TNY_ACCOUNT_TYPE_TRANSPORT);
538                                 if (protocol && MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
539                                         ModestPairList *pair_list;
540                                         pair_list = modest_account_protocol_get_from_list (MODEST_ACCOUNT_PROTOCOL (protocol),
541                                                                                            account_name);
542                                         if (pair_list) {
543                                                 transports = g_slist_concat (transports, pair_list);
544                                                 multi_mailbox = TRUE;
545                                         }
546                                 }
547                         }
548
549                         if (!multi_mailbox) {
550                                 gchar *from_string  = NULL;
551
552                                 from_string = modest_account_mgr_get_from_string (account_mgr,
553                                                                                   account_name, NULL);
554                                 if (from_string && account_name) {
555                                         gchar *name = account_name;
556                                         ModestPair *pair = modest_pair_new ((gpointer) name,
557                                                                             (gpointer) from_string , TRUE);
558                                         transports = g_slist_prepend (transports, pair);
559                                 }
560                         }
561                 }
562                 
563                 cursor = cursor->next;
564         }
565         g_slist_free (accounts); /* only free the accounts, not the elements,
566                                   * because they are used in the pairlist */
567         return transports;
568 }
569
570 static void window_focus (GtkWindow *window,
571                           GtkWidget *widget,
572                           gpointer userdata)
573 {
574         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
575 }
576
577 gboolean
578 scroll_drag_timeout (gpointer userdata)
579 {
580         ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
581         ModestMsgEditWindowPrivate *priv;
582
583         /* It could happen that the window was already closed */
584         if (!GTK_WIDGET_VISIBLE (win))
585                 return FALSE;
586
587         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
588
589         correct_scroll_without_drag_check (win, TRUE);
590
591         priv->scroll_drag_timeout_id = 0;
592
593         return FALSE;
594 }
595
596 static gboolean 
597 correct_scroll_without_drag_check_idle (gpointer userdata)
598 {
599         ModestMsgEditWindow *w = (ModestMsgEditWindow *) userdata;
600         ModestMsgEditWindowPrivate *priv;
601         GtkTextIter iter;
602         GdkRectangle rectangle;
603         gint offset_min, offset_max;
604         GtkTextMark *insert;
605         GtkAdjustment *vadj;
606
607         /* It could happen that the window was already closed */
608         if (!GTK_WIDGET_VISIBLE (w))
609                 return FALSE;
610
611         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
612
613         insert = gtk_text_buffer_get_insert (priv->text_buffer);
614         gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
615
616         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
617         offset_min = priv->msg_body->allocation.y + rectangle.y;
618         offset_max = offset_min + rectangle.height;
619
620         vadj = hildon_pannable_area_get_vadjustment (HILDON_PANNABLE_AREA (priv->pannable));
621         offset_min = MAX (offset_min - 48, 0);
622         offset_max = MIN (offset_max + 48, vadj->upper);
623
624         gtk_adjustment_clamp_page (vadj, (gdouble) offset_min, (gdouble) offset_max);
625
626         priv->correct_scroll_idle = 0;
627         return FALSE;
628 }
629
630 static void
631 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
632 {
633         ModestMsgEditWindowPrivate *priv;
634
635         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
636
637         if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
638                 return;
639
640         if (priv->correct_scroll_idle > 0) {
641                 return;
642         }
643
644         priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
645                                                      (GSourceFunc) correct_scroll_without_drag_check_idle,
646                                                      g_object_ref (w),
647                                                      g_object_unref);
648 }
649
650 static void
651 correct_scroll (ModestMsgEditWindow *w)
652 {
653         ModestMsgEditWindowPrivate *priv;
654
655         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
656         if (gtk_grab_get_current () == priv->msg_body) {
657                 if (priv->scroll_drag_timeout_id == 0) {
658                         priv->scroll_drag_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
659                                                                            500,
660                                                                            (GSourceFunc) scroll_drag_timeout,
661                                                                            g_object_ref (w),
662                                                                            g_object_unref);
663                 }
664                 return;
665         }
666
667         correct_scroll_without_drag_check (w, TRUE);
668 }
669
670 static void
671 text_buffer_end_user_action (GtkTextBuffer *buffer,
672                              ModestMsgEditWindow *userdata)
673 {
674
675         correct_scroll (userdata);
676 }
677
678 static void
679 text_buffer_mark_set (GtkTextBuffer *buffer,
680                       GtkTextIter *iter,
681                       GtkTextMark *mark,
682                       ModestMsgEditWindow *userdata)
683 {
684         gtk_text_buffer_begin_user_action (buffer);
685         gtk_text_buffer_end_user_action (buffer);
686 }
687
688 static void
689 cut_clipboard_check (GtkTextView *text_view,
690                      gpointer userdata)
691 {
692         GtkTextBuffer *buffer;
693         
694         buffer = gtk_text_view_get_buffer (text_view);
695         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
696                 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
697         }
698 }
699
700 static void
701 copy_clipboard_check (GtkTextView *text_view,
702                      gpointer userdata)
703 {
704         GtkTextBuffer *buffer;
705         
706         buffer = gtk_text_view_get_buffer (text_view);
707         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
708                 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
709         }
710 }
711
712 static void
713 attachment_deleted (ModestAttachmentsView *attachments_view,
714                     gpointer user_data)
715 {
716         modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
717                                                    NULL);
718 }
719
720 static void
721 body_size_request (GtkWidget *body,
722                    GtkRequisition *req,
723                    gpointer user_data)
724 {
725         /* Make sure the body always get at least 70 pixels */
726         if (req->height < 70)
727                 req->height = 70;
728 }
729
730 static void
731 connect_signals (ModestMsgEditWindow *obj)
732 {
733         ModestMsgEditWindowPrivate *priv;
734
735         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
736
737         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
738                           G_CALLBACK (text_buffer_refresh_attributes), obj);
739         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
740                           G_CALLBACK (text_buffer_can_undo), obj);
741         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
742                           G_CALLBACK (text_buffer_can_redo), obj);
743         g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
744                           G_CALLBACK (body_changed), obj);
745         g_signal_connect (G_OBJECT (priv->text_buffer), "insert-text", 
746                           G_CALLBACK (body_insert_text), obj);
747         g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
748                           G_CALLBACK (body_changed), obj);
749         g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
750                           G_CALLBACK (text_buffer_end_user_action), obj);
751         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
752                           G_CALLBACK (text_buffer_mark_set), obj);
753         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
754                                 G_CALLBACK (text_buffer_apply_tag), obj);
755         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
756                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
757         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
758                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
759         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
760                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
761
762         g_signal_connect (G_OBJECT (priv->send_button), "clicked",
763                           G_CALLBACK (modest_ui_actions_on_send), obj);
764
765         g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
766                           G_CALLBACK (from_field_changed), obj);
767
768         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
769                           G_CALLBACK (msg_body_focus), obj);
770         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
771                           G_CALLBACK (msg_body_focus), obj);
772         g_signal_connect (G_OBJECT (priv->msg_body), "size-request",
773                           G_CALLBACK (body_size_request), obj);
774         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
775         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
776                           "changed", G_CALLBACK (recpt_field_changed), obj);
777         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
778                           "changed", G_CALLBACK (recpt_field_changed), obj);
779         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
780                           "changed", G_CALLBACK (recpt_field_changed), obj);
781         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
782         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
783         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
784
785         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
786         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
787  
788         priv->clipboard_change_handler_id = 
789                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
790                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
791         priv->default_clipboard_change_handler_id = 
792                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
793                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
794
795         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
796         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
797         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
798 }
799
800 static void
801 init_wp_text_view_style ()
802 {
803         static gboolean initialized = FALSE;
804
805         if (!initialized) {
806                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
807                 initialized = TRUE;
808         }
809 }       
810
811 static void
812 init_window (ModestMsgEditWindow *obj)
813 {
814         GtkWidget *to_caption, *subject_caption;
815         GtkWidget *main_vbox;
816         ModestMsgEditWindowPrivate *priv;
817         GtkActionGroup *action_group;
818         ModestWindowPrivate *parent_priv;
819         GdkPixbuf *window_icon = NULL;
820         GError *error = NULL;
821
822         GtkSizeGroup *title_size_group;
823         GtkSizeGroup *value_size_group;
824         GtkWidget *window_box;
825         GtkWidget *window_align;
826 #if (GTK_MINOR_VERSION >= 10)
827         GdkAtom deserialize_type;
828 #endif
829         GtkWidget *from_send_hbox;
830         GtkWidget *send_icon;
831         GtkWidget *attachments_label;
832         GtkWidget *branding_box;
833
834         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
835         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
836
837         parent_priv->ui_manager = gtk_ui_manager_new();
838         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
839         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
840
841         /* Add common actions */
842         gtk_action_group_add_actions (action_group,
843                                       modest_msg_edit_action_entries,
844                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
845                                       obj);
846         gtk_action_group_add_actions (action_group,
847                                       hildon2_msg_edit_action_entries,
848                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
849                                       obj);
850         gtk_action_group_add_toggle_actions (action_group,
851                                              modest_msg_edit_toggle_action_entries,
852                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
853                                              obj);
854         gtk_action_group_add_radio_actions (action_group,
855                                             modest_msg_edit_alignment_radio_action_entries,
856                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
857                                             GTK_JUSTIFY_LEFT,
858                                             G_CALLBACK (modest_ui_actions_on_change_justify),
859                                             obj);
860         gtk_action_group_add_radio_actions (action_group,
861                                             modest_msg_edit_priority_action_entries,
862                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
863                                             0,
864                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
865                                             obj);
866         gtk_action_group_add_radio_actions (action_group,
867                                             modest_msg_edit_file_format_action_entries,
868                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
869                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
870                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
871                                             obj);
872         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
873         g_object_unref (action_group);
874
875         /* Load the UI definition */
876         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
877                                          &error);
878         if (error != NULL) {
879                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
880                 g_clear_error (&error);
881         }
882
883         /* Add accelerators */
884         gtk_window_add_accel_group (GTK_WINDOW (obj), 
885                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
886
887         parent_priv->menubar = NULL;
888
889         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
890         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
891
892         /* Note: This ModestPairList* must exist for as long as the picker
893          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
894          * so it can't know how to manage its memory. */ 
895         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
896                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
897                                                           NULL, g_str_equal);
898         modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
899         modest_maemo_utils_set_hbutton_layout (title_size_group, NULL, 
900                                                _("mail_va_from"), priv->from_field);
901         hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
902         hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
903         hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
904
905         priv->to_field      = modest_recpt_editor_new ();
906         priv->cc_field      = modest_recpt_editor_new ();
907         priv->bcc_field     = modest_recpt_editor_new ();
908         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
909         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
910         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
911         priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
912         priv->priority_icon = gtk_image_new ();
913         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
914         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
915         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
916         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
917         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
918                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
919         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
920         priv->attachments_view = modest_attachments_view_new (NULL);
921         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
922                                            MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
923         
924         priv->header_box = gtk_vbox_new (FALSE, 0);
925         
926         to_caption = _create_addressbook_box
927                 (title_size_group, value_size_group,
928                  _("mail_va_to"), priv->to_field);
929         priv->cc_caption = _create_addressbook_box
930                 (title_size_group, value_size_group,
931                  _("mail_va_cc"), priv->cc_field);
932         priv->bcc_caption = _create_addressbook_box
933                 (title_size_group, value_size_group,
934                  _("mail_va_hotfix1"), priv->bcc_field);
935         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
936                                                                _("mail_va_subject"), FALSE, priv->subject_box);
937         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
938                                                                                         _("mail_va_attachment"), 
939                                                                                         FALSE,
940                                                                                         priv->attachments_view,
941                                                                                         HILDON_SIZE_AUTO_WIDTH |
942                                                                                         HILDON_SIZE_AUTO_HEIGHT);
943         attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
944         hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
945
946
947         priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
948         send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
949         gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
950         gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
951
952         g_object_unref (title_size_group);
953         g_object_unref (value_size_group);
954
955         priv->brand_icon = gtk_image_new ();
956         gtk_misc_set_alignment (GTK_MISC (priv->brand_icon), 0.5, 0.5);
957         priv->brand_label = gtk_label_new (NULL);
958         hildon_helper_set_logical_font (priv->brand_label, "SmallSystemFont");
959         gtk_misc_set_alignment (GTK_MISC (priv->brand_label), 0.0, 0.5);
960         gtk_widget_set_no_show_all (priv->brand_icon, TRUE);
961         gtk_widget_set_no_show_all (priv->brand_label, TRUE);
962
963         from_send_hbox = gtk_hbox_new (FALSE, 0);
964         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
965         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
966
967         branding_box = gtk_hbox_new (FALSE, MODEST_MARGIN_DEFAULT);
968         gtk_widget_show (branding_box);
969         gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_label, FALSE, FALSE, 0);
970         gtk_box_pack_start (GTK_BOX (branding_box), priv->brand_icon, FALSE, FALSE, 0);
971
972         priv->brand_container = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
973         gtk_alignment_set_padding (GTK_ALIGNMENT (priv->brand_container), 0, 0, MODEST_MARGIN_DOUBLE, 0);
974         gtk_container_add (GTK_CONTAINER (priv->brand_container), branding_box);
975         gtk_widget_set_no_show_all (priv->brand_container, TRUE);
976
977
978         gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
979         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
980         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
981         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
982         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
983         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
984         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->brand_container, FALSE, FALSE, 0);
985         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
986
987         init_wp_text_view_style ();
988
989         priv->msg_body = modest_wp_text_view_new ();
990         
991
992         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
993         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
994         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
995         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
996 #if (GTK_MINOR_VERSION >= 10)
997         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
998         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
999                                                                        NULL);
1000         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
1001                                                          deserialize_type, TRUE);
1002 #endif
1003         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1004
1005         priv->find_toolbar = hildon_find_toolbar_new (NULL);
1006         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
1007
1008 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
1009
1010         priv->pannable = hildon_pannable_area_new ();
1011
1012         g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
1013         
1014         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
1015         window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
1016         gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
1017
1018         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
1019         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
1020         gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
1021
1022         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
1023         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
1024         
1025         window_box = gtk_vbox_new (FALSE, 0);
1026         gtk_container_add (GTK_CONTAINER(obj), window_box);
1027
1028         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
1029
1030         /* Set window icon */
1031         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
1032         if (window_icon) {
1033                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1034                 g_object_unref (window_icon);
1035         }       
1036 }
1037         
1038 static void
1039 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
1040 {
1041         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1042
1043         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1044             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1045                                            priv->clipboard_change_handler_id))
1046                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1047                                              priv->clipboard_change_handler_id);
1048         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1049             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1050                                            priv->default_clipboard_change_handler_id))
1051                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1052                                              priv->default_clipboard_change_handler_id);
1053
1054         if (priv->account_removed_handler_id && 
1055             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
1056                                            priv->account_removed_handler_id))
1057                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
1058                                            priv->account_removed_handler_id);
1059 }
1060
1061 static void
1062 modest_msg_edit_window_finalize (GObject *obj)
1063 {
1064         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1065
1066         if (priv->max_chars_banner) {
1067                 g_object_weak_unref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, obj);
1068                 priv->max_chars_banner = FALSE;
1069         }
1070
1071         /* Sanity check: shouldn't be needed, the window mgr should
1072            call this function before */
1073         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1074
1075         if (priv->font_dialog != NULL) {
1076                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1077         }
1078
1079         if (priv->clipboard_text != NULL) {
1080                 g_free (priv->clipboard_text);
1081                 priv->clipboard_text = NULL;
1082         }
1083         
1084         if (priv->draft_msg != NULL) {
1085                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1086                 if (TNY_IS_HEADER (header)) {
1087                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1088                         modest_window_mgr_unregister_header (mgr, header);
1089                 }
1090                 g_object_unref (priv->draft_msg);
1091                 priv->draft_msg = NULL;
1092         }
1093         if (priv->outbox_msg != NULL) {
1094                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1095                 if (TNY_IS_HEADER (header)) {
1096                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1097                         modest_window_mgr_unregister_header (mgr, header);
1098                 }
1099                 g_object_unref (priv->outbox_msg);
1100                 priv->outbox_msg = NULL;
1101         }
1102         if (priv->correct_scroll_idle > 0) {
1103                 g_source_remove (priv->correct_scroll_idle);
1104                 priv->correct_scroll_idle = 0;
1105         }
1106         if (priv->scroll_drag_timeout_id > 0) {
1107                 g_source_remove (priv->scroll_drag_timeout_id);
1108                 priv->scroll_drag_timeout_id = 0;
1109         }
1110         if (priv->clipboard_owner_idle > 0) {
1111                 g_source_remove (priv->clipboard_owner_idle);
1112                 priv->clipboard_owner_idle = 0;
1113         }
1114         if (priv->original_account_name)
1115                 g_free (priv->original_account_name);
1116         if (priv->original_mailbox)
1117                 g_free (priv->original_mailbox);
1118         g_free (priv->msg_uid);
1119         g_free (priv->last_search);
1120         g_free (priv->references);
1121         g_free (priv->in_reply_to);
1122         g_object_unref (priv->attachments);
1123         g_object_unref (priv->images);
1124
1125         /* This had to stay alive for as long as the picker that used it: */
1126         modest_pair_list_free (priv->from_field_protos);
1127         
1128         G_OBJECT_CLASS(parent_class)->finalize (obj);
1129 }
1130
1131 static void
1132 pixbuf_size_prepared (GdkPixbufLoader *loader,
1133                       gint width,
1134                       gint height,
1135                       ModestMsgEditWindow *self)
1136 {
1137         gint new_height, new_width;
1138         gboolean set_size;
1139         
1140         new_height = height;
1141         new_width = width;
1142         set_size = FALSE;
1143
1144         if (width > IMAGE_MAX_WIDTH) {
1145                 new_height = height * IMAGE_MAX_WIDTH / width;
1146                 new_width = IMAGE_MAX_WIDTH;
1147         }
1148
1149         gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1150 }
1151
1152 static GdkPixbuf *
1153 pixbuf_from_stream (TnyStream *stream,
1154                     const gchar *mime_type,
1155                     guint64 *stream_size,
1156                     ModestMsgEditWindow *self)
1157 {
1158         GdkPixbufLoader *loader;
1159         GdkPixbuf *pixbuf;
1160         guint64 size;
1161         GError *error = NULL;
1162
1163         size = 0;
1164
1165         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1166
1167         if (loader == NULL) {
1168                 if (stream_size)
1169                         *stream_size = 0;
1170                 return NULL;
1171         }
1172         g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1173
1174         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1175
1176         tny_stream_reset (TNY_STREAM (stream));
1177         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1178                 unsigned char read_buffer[128];
1179                 gint readed;
1180                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1181                 size += readed;
1182                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1183                         break;
1184                 }
1185                 /* Allow some UI responsiveness */
1186                 while (gtk_events_pending ())
1187                         gtk_main_iteration ();
1188         }
1189         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1190
1191         gdk_pixbuf_loader_close (loader, &error);
1192
1193         if (error)
1194                 g_error_free (error);
1195         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1196         if (pixbuf) 
1197                 g_object_ref (pixbuf);
1198         g_object_unref (loader);
1199
1200         if (!pixbuf)
1201                 return NULL;
1202
1203         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1204                 GdkPixbuf *new_pixbuf;
1205                 gint new_height;
1206                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1207                         gdk_pixbuf_get_width (pixbuf);
1208                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1209                 g_object_unref (pixbuf);
1210                 pixbuf = new_pixbuf;
1211         }
1212
1213         if (stream_size)
1214                 *stream_size = size;
1215
1216         return pixbuf;
1217 }
1218
1219 static void
1220 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1221 {
1222         ModestMsgEditWindowPrivate *priv;
1223         TnyIterator *iter;
1224
1225         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1226
1227         g_object_ref (self);
1228         for (iter = tny_list_create_iterator (attachments);
1229              !tny_iterator_is_done (iter);
1230              tny_iterator_next (iter)) {
1231                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1232                 const gchar *cid = tny_mime_part_get_content_id (part);
1233                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1234                 if ((cid != NULL)&&(mime_type != NULL)) {
1235                         guint64 stream_size;
1236                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1237                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1238
1239
1240                         g_object_unref (stream);
1241
1242                         if (pixbuf != NULL) {
1243                                 priv->images_count ++;
1244                                 priv->images_size += stream_size;
1245                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1246                                 g_object_unref (pixbuf);
1247                         }
1248                 }
1249                 g_object_unref (part);
1250         }
1251         g_object_unref (iter);
1252         g_object_unref (self);
1253 }
1254
1255 static void
1256 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1257 {
1258         TnyMimePart *parent = NULL;
1259         const gchar *content_type = NULL;
1260         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1261
1262         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1263
1264         if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1265                 parent = g_object_ref (msg);
1266         } else if (content_type && !g_ascii_strcasecmp (content_type, "multipart/mixed")) {
1267                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1268                 TnyIterator *iter;
1269
1270                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1271                 iter = tny_list_create_iterator (parts);
1272                 while (!tny_iterator_is_done (iter)) {
1273                         TnyMimePart *part;
1274                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1275                         content_type = tny_mime_part_get_content_type (part);
1276                         if (content_type && !g_ascii_strcasecmp (content_type, "multipart/related")) {
1277                                 parent = part;
1278                                 break;
1279                         } else {
1280                                 g_object_unref (part);
1281                         }
1282                         tny_iterator_next (iter);
1283                 }
1284                 g_object_unref (iter);
1285                 g_object_unref (parts);
1286         }
1287
1288         if (parent != NULL) {
1289                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1290                 TnyIterator *iter;
1291
1292                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1293                 iter = tny_list_create_iterator (parts);
1294                 while (!tny_iterator_is_done (iter)) {
1295                         TnyMimePart *part;
1296                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1297                         content_type = tny_mime_part_get_content_type (part);
1298                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1299                                 tny_list_prepend (priv->images, (GObject *) part);
1300                         } 
1301                         g_object_unref (part);
1302                         tny_iterator_next (iter);
1303                 }
1304                 g_object_unref (iter);
1305                 g_object_unref (parts);
1306                 g_object_unref (parent);
1307         }
1308 }
1309
1310 static void
1311 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1312 {
1313         TnyIterator *iter;
1314         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1315
1316         for (iter = tny_list_create_iterator (attachments) ; 
1317              !tny_iterator_is_done (iter);
1318              tny_iterator_next (iter)) {
1319                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1320                 const gchar *cid = tny_mime_part_get_content_id (part);
1321                 if (cid != NULL) {
1322                         char *invalid = NULL;
1323                         gint int_cid = strtol (cid, &invalid, 10);
1324                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1325                                 priv->next_cid = int_cid + 1;
1326                         }
1327                 }
1328                 g_object_unref (part);
1329         }
1330         g_object_unref (iter);
1331 }
1332
1333 static void
1334 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1335 {
1336         TnyHeader *header;
1337         gchar *to, *cc, *bcc, *subject;
1338         gchar *body;
1339         ModestMsgEditWindowPrivate *priv;
1340         ModestWindowPrivate *parent_priv;
1341         GtkTextIter iter;
1342         TnyHeaderFlags priority_flags;
1343         TnyFolder *msg_folder;
1344         gboolean is_html = FALSE;
1345         gboolean field_view_set;
1346         
1347         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1348         g_return_if_fail (TNY_IS_MSG (msg));
1349
1350         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1351         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1352
1353         header = tny_msg_get_header (msg);
1354         to      = tny_header_dup_to (header);
1355         cc      = tny_header_dup_cc (header);
1356         bcc     = tny_header_dup_bcc (header);
1357         subject = tny_header_dup_subject (header);
1358
1359         modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1360         priority_flags = tny_header_get_priority (header);
1361
1362         if (to) {
1363                 gchar *quoted_names = modest_text_utils_quote_names (to);
1364                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field), quoted_names);
1365                 g_free (quoted_names);
1366         }
1367
1368         field_view_set = TRUE;
1369         if (cc) {
1370                 gchar *quoted_names = modest_text_utils_quote_names (cc);
1371                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  quoted_names);
1372                 g_free (quoted_names);
1373                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1374                 gtk_widget_show (priv->cc_caption);
1375         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1376                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1377                 gtk_widget_hide (priv->cc_caption);
1378                 field_view_set = FALSE;
1379         }
1380         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1381
1382         field_view_set = TRUE;
1383         if (bcc) {
1384                 gchar *quoted_names = modest_text_utils_quote_names (bcc);
1385                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), quoted_names);
1386                 g_free (quoted_names);
1387                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1388                 gtk_widget_show (priv->bcc_caption);
1389         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1390                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1391                 gtk_widget_hide (priv->bcc_caption);
1392                 field_view_set = FALSE;
1393         }
1394         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1395
1396
1397         if (subject)
1398                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1399         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1400                                                    priority_flags);
1401
1402         update_window_title (self);
1403
1404         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1405         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1406
1407         if ((body == NULL)||(body[0] == '\0')) {
1408                 g_free (body);
1409                 body = modest_text_utils_convert_to_html ("");
1410                 is_html = FALSE;
1411         }
1412         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1413         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1414                                             (gchar *) body,
1415                                             strlen (body));
1416         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1417         g_free (body);
1418
1419         /* Add attachments to the view */
1420         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1421         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1422         if (tny_list_get_length (priv->attachments) == 0) {
1423                 gtk_widget_hide (priv->attachments_caption);
1424         } else {
1425                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1426                 gtk_widget_show_all (priv->attachments_caption);
1427         }
1428         get_related_images (self, msg);
1429         update_next_cid (self, priv->attachments);
1430         update_next_cid (self, priv->images);
1431         replace_with_images (self, priv->images);
1432
1433         if (preserve_is_rich && !is_html) {
1434                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1435         /* Get the default format required from configuration */
1436         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1437                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1438         }
1439
1440         /* Set the default focus depending on having already a To: field or not */
1441         if ((!to)||(*to == '\0')) {
1442                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1443         } else {
1444                 gtk_widget_grab_focus (priv->msg_body);
1445         }
1446
1447         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1448
1449         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1450         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1451
1452         modest_msg_edit_window_set_modified (self, FALSE);
1453
1454         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1455         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1456         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1457         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1458
1459         if (priv->msg_uid) {
1460                 g_free (priv->msg_uid);
1461                 priv->msg_uid = NULL;
1462         }
1463
1464         /* we should set a reference to the incoming message if it is a draft */
1465         msg_folder = tny_msg_get_folder (msg);
1466         if (msg_folder) {               
1467                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1468                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1469                         if (type == TNY_FOLDER_TYPE_INVALID)
1470                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1471                         
1472                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1473                                 priv->draft_msg = g_object_ref(msg);
1474                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1475                                 priv->outbox_msg = g_object_ref(msg);
1476                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1477                 }
1478                 g_object_unref (msg_folder);
1479         }
1480
1481         g_free (to);
1482         g_free (subject);
1483         g_free (cc);
1484         g_free (bcc);
1485 }
1486
1487
1488 static void
1489 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1490 {
1491         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1492         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1493         GtkWidget *placeholder;
1494         GtkWidget *tool_item;
1495         gint insert_index;
1496         gchar size_text[5];
1497         gint size_index;
1498         gint font_index;
1499         GtkWidget *sizes_menu;
1500         GtkWidget *fonts_menu;
1501         gchar *markup;
1502         GtkWidget *arrow;
1503         GtkWidget *hbox;
1504
1505         /* Toolbar */
1506         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1507         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1508         gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1509         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1510
1511         /* Font color placeholder */
1512         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1513         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1514
1515         /* font color */
1516         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1517         priv->font_color_button = hildon_color_button_new ();
1518         gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1519         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1520         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1521         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1522         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1523         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1524         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1525         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1526                                   "notify::color", 
1527                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1528                                   window);
1529
1530         /* Font size and face placeholder */
1531         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1532         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1533         /* font_size */
1534         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1535         priv->size_tool_button_label = gtk_label_new (NULL);
1536         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1537         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1538                               size_text, "</span>", NULL);
1539         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1540         gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1541         g_free (markup);
1542         hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1543         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1544         gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1545         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1546         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1547         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1548         gtk_widget_set_sensitive (arrow, FALSE);
1549         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1550         sizes_menu = gtk_menu_new ();
1551         priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1552         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1553                 GtkTreeIter iter;
1554
1555                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1556                 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1557
1558                 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter, 
1559                                     0, size_text,
1560                                     -1);
1561
1562                 if (wp_font_size[size_index] == 12)
1563                         priv->current_size_index = size_index;
1564                                         
1565         }
1566
1567         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1568         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1569         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1570         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1571         priv->font_size_toolitem = tool_item;
1572
1573         /* font face */
1574         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1575         priv->font_tool_button_label = gtk_label_new (NULL);
1576         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1577         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1578         gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1579         g_free(markup);
1580         hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1581         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1582         gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1583         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1584         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1585         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1586         gtk_widget_set_sensitive (arrow, FALSE);
1587         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1588         fonts_menu = gtk_menu_new ();
1589         priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1590         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1591                 GtkTreeIter iter;
1592
1593                 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1594
1595                 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter, 
1596                                     0, wp_get_font_name (font_index),
1597                                     -1);
1598
1599                 if (font_index == DEFAULT_FONT)
1600                         priv->current_face_index = font_index;
1601         }
1602         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1603         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1604         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1605         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1606         priv->font_face_toolitem = tool_item;
1607
1608         /* Set expand and homogeneous for remaining items */
1609         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1610         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1611         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1612         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1613         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1614         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1615
1616         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1617            will not show the tool items added to the placeholders) */
1618         gtk_widget_show_all (parent_priv->toolbar);
1619
1620         /* Set the no show all *after* showing all items. We do not
1621            want the toolbar to be shown with a show all because it
1622            could go agains the gconf setting regarding showing or not
1623            the toolbar of the editor window */
1624         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1625 }
1626
1627
1628
1629 ModestWindow*
1630 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1631 {
1632         GObject *obj;
1633         ModestWindowPrivate *parent_priv;
1634         ModestMsgEditWindowPrivate *priv;
1635         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1636         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1637         ModestWindowMgr *mgr = NULL;
1638
1639         g_return_val_if_fail (msg, NULL);
1640         g_return_val_if_fail (account_name, NULL);
1641
1642         mgr = modest_runtime_get_window_mgr ();
1643         
1644         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1645
1646         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1647         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1648
1649         /* Menubar. Update the state of some toggles */
1650         priv->from_field_protos = get_transports ();
1651         priv->original_mailbox = NULL;
1652         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1653         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1654         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1655         if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1656                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1657                 priv->original_mailbox = g_strdup (mailbox);
1658         } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1659                 /* We set the first mailbox as the active mailbox */
1660                 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1661                 if (priv->original_mailbox != NULL)
1662                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1663                                                               (gpointer) priv->original_mailbox);
1664                 else
1665                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1666                                                               (gpointer) account_name);
1667         } else {
1668                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1669         }
1670         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1671         update_branding (MODEST_MSG_EDIT_WINDOW (obj), priv->last_from_account);
1672         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1673                                  _("mail_va_from"));
1674         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1675                                  hildon_touch_selector_get_current_text 
1676                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1677         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1678         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1679
1680         /* Init window */
1681         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1682
1683         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1684                 
1685         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1686         modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1687
1688         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1689
1690         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1691         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1692         /* Add common dimming rules */
1693         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1694                                               modest_msg_edit_window_toolbar_dimming_entries,
1695                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1696                                               MODEST_WINDOW (obj));
1697         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_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_size_toolitem,
1701                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1702                                                     MODEST_WINDOW (obj));
1703         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1704                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1705                                                     MODEST_WINDOW (obj));
1706         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1707                                                     G_CALLBACK (modest_ui_dimming_rules_on_send),
1708                                                     MODEST_WINDOW (obj));
1709         /* Insert dimming rules group for this window */
1710         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1711         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1712
1713         /* Setup app menu */
1714         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1715
1716         /* Checks the dimming rules */
1717         g_object_unref (toolbar_rules_group);
1718         g_object_unref (clipboard_rules_group);
1719         gtk_widget_hide (priv->priority_icon);
1720         gtk_widget_queue_resize (priv->subject_box);
1721         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1722
1723         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1724
1725         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1726         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1727         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1728         priv->update_caption_visibility = TRUE;
1729
1730         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1731
1732         /* Track account-removed signal, this window should be closed
1733            in the case we're creating a mail associated to the account
1734            that is deleted */
1735         priv->account_removed_handler_id = 
1736                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1737                                   "account_removed",
1738                                   G_CALLBACK(on_account_removed),
1739                                   obj);
1740
1741         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1742
1743         return (ModestWindow*) obj;
1744 }
1745
1746 static gint
1747 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1748 {
1749         GString **string_buffer = (GString **) user_data;
1750
1751         *string_buffer = g_string_append (*string_buffer, buffer);
1752    
1753         return 0;
1754 }
1755
1756 /**
1757  * @result: A new string which should be freed with g_free().
1758  */
1759 static gchar *
1760 get_formatted_data (ModestMsgEditWindow *edit_window)
1761 {
1762         ModestMsgEditWindowPrivate *priv;
1763         GString *string_buffer = g_string_new ("");
1764         
1765         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1766
1767         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1768
1769         modest_text_utils_hyperlinkify (string_buffer);
1770
1771         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1772
1773         return g_string_free (string_buffer, FALSE);
1774                                                                         
1775 }
1776
1777 MsgData * 
1778 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1779 {
1780         MsgData *data;
1781         const gchar *account_name;
1782         ModestMsgEditWindowPrivate *priv;
1783         TnyIterator *att_iter;
1784         const gchar *picker_active_id;
1785         
1786         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1787
1788         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1789         
1790         picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1791         g_return_val_if_fail (picker_active_id, NULL);
1792         account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1793         
1794         /* don't free these (except from) */
1795         data = g_slice_new0 (MsgData);
1796         data->from    =  g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1797         data->account_name = g_strdup (account_name);
1798         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1799         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1800         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1801         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1802         data->references = g_strdup (priv->references);
1803         data->in_reply_to = g_strdup (priv->in_reply_to);
1804         if (priv->draft_msg) {
1805                 data->draft_msg = g_object_ref (priv->draft_msg);
1806         } else if (priv->outbox_msg) {
1807                 data->draft_msg = g_object_ref (priv->outbox_msg);
1808         } else {
1809                 data->draft_msg = NULL;
1810         }
1811
1812         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1813         GtkTextIter b, e;
1814         gtk_text_buffer_get_bounds (buf, &b, &e);
1815         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1816
1817         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1818                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1819         else
1820                 data->html_body = NULL;
1821
1822         /* deep-copy the data */
1823         att_iter = tny_list_create_iterator (priv->attachments);
1824         data->attachments = NULL;
1825         while (!tny_iterator_is_done (att_iter)) {
1826                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1827                 if (!(TNY_IS_MIME_PART(part))) {
1828                         g_warning ("strange data in attachment list");
1829                         g_object_unref (part);
1830                         tny_iterator_next (att_iter);
1831                         continue;
1832                 }
1833                 data->attachments = g_list_append (data->attachments,
1834                                                    part);
1835                 tny_iterator_next (att_iter);
1836         }
1837         g_object_unref (att_iter);
1838
1839         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1840         att_iter = tny_list_create_iterator (priv->images);
1841         data->images = NULL;
1842         while (!tny_iterator_is_done (att_iter)) {
1843                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1844                 const gchar *cid;
1845                 if (!(TNY_IS_MIME_PART(part))) {
1846                         g_warning ("strange data in attachment list");
1847                         g_object_unref (part);
1848                         tny_iterator_next (att_iter);
1849                         continue;
1850                 }
1851                 cid = tny_mime_part_get_content_id (part);
1852                 if (cid) {                      
1853                         gchar *image_tag_id;
1854                         GtkTextTag *image_tag;
1855                         GtkTextIter iter;
1856                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1857                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1858                         g_free (image_tag_id);
1859                         
1860                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1861                         if (image_tag && 
1862                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1863                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1864                                 data->images = g_list_append (data->images,
1865                                                               g_object_ref (part));
1866                 }
1867                 g_object_unref (part);
1868                 tny_iterator_next (att_iter);
1869         }
1870         g_object_unref (att_iter);
1871         
1872         data->priority_flags = priv->priority_flags;
1873
1874         return data;
1875 }
1876
1877
1878 static void
1879 unref_gobject (GObject *obj, gpointer data)
1880 {
1881         if (!G_IS_OBJECT(obj))
1882                 return;
1883         g_object_unref (obj);
1884 }
1885
1886 void 
1887 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1888                                                       MsgData *data)
1889 {
1890         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1891
1892         if (!data)
1893                 return;
1894
1895         g_free (data->to);
1896         g_free (data->cc);
1897         g_free (data->bcc);
1898         g_free (data->from);
1899         g_free (data->subject);
1900         g_free (data->plain_body);
1901         g_free (data->html_body);
1902         g_free (data->account_name);
1903         g_free (data->references);
1904         g_free (data->in_reply_to);
1905         
1906         if (data->draft_msg != NULL) {
1907                 g_object_unref (data->draft_msg);
1908                 data->draft_msg = NULL;
1909         }
1910         
1911         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1912         g_list_free (data->attachments);
1913         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1914         g_list_free (data->images);
1915         
1916         g_slice_free (MsgData, data);
1917 }
1918
1919 void                    
1920 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1921                                        gint *parts_count,
1922                                        guint64 *parts_size)
1923 {
1924         ModestMsgEditWindowPrivate *priv;
1925
1926         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1927
1928         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1929
1930         /* TODO: add images */
1931         *parts_size += priv->images_size;
1932         *parts_count += priv->images_count;
1933
1934 }
1935
1936 ModestMsgEditFormat
1937 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1938 {
1939         gboolean rich_text;
1940         ModestMsgEditWindowPrivate *priv = NULL;
1941         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1942
1943         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1944
1945         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1946         if (rich_text)
1947                 return MODEST_MSG_EDIT_FORMAT_HTML;
1948         else
1949                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1950 }
1951
1952 void
1953 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1954                                    ModestMsgEditFormat format)
1955 {
1956         ModestMsgEditWindowPrivate *priv;
1957         ModestWindowPrivate *parent_priv;
1958
1959         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1960         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1961         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1962
1963         switch (format) {
1964         case MODEST_MSG_EDIT_FORMAT_HTML:
1965                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1966                 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1967                 break;
1968         case MODEST_MSG_EDIT_FORMAT_TEXT:
1969                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1970                 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1971                 break;
1972         default:
1973                 g_return_if_reached ();
1974         }
1975 }
1976
1977 ModestMsgEditFormatState *
1978 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1979 {
1980         ModestMsgEditFormatState *format_state = NULL;
1981         ModestMsgEditWindowPrivate *priv;
1982         WPTextBufferFormat *buffer_format;
1983
1984         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1985
1986         buffer_format = g_new0 (WPTextBufferFormat, 1);
1987         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1988
1989         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1990
1991         format_state = g_new0 (ModestMsgEditFormatState, 1);
1992         format_state->bold = buffer_format->bold&0x1;
1993         format_state->italics = buffer_format->italic&0x1;
1994         format_state->bullet = buffer_format->bullet&0x1;
1995         format_state->color = buffer_format->color;
1996         format_state->font_size = buffer_format->font_size;
1997         format_state->font_family = wp_get_font_name (buffer_format->font);
1998         format_state->justification = buffer_format->justification;
1999         g_free (buffer_format);
2000
2001         return format_state;
2002  
2003 }
2004
2005 void
2006 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
2007                                          const ModestMsgEditFormatState *format_state)
2008 {
2009         ModestMsgEditWindowPrivate *priv;
2010         WPTextBufferFormat *buffer_format;
2011         WPTextBufferFormat *current_format;
2012
2013         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2014         g_return_if_fail (format_state != NULL);
2015
2016         buffer_format = g_new0 (WPTextBufferFormat, 1);
2017         current_format = g_new0 (WPTextBufferFormat, 1);
2018
2019         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2020         gtk_widget_grab_focus (priv->msg_body);
2021         buffer_format->bold = (format_state->bold != FALSE);
2022         buffer_format->italic = (format_state->italics != FALSE);
2023         buffer_format->color = format_state->color;
2024         buffer_format->font_size = format_state->font_size;
2025         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
2026         buffer_format->justification = format_state->justification;
2027         buffer_format->bullet = format_state->bullet;
2028
2029         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
2030
2031         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
2032         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
2033         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
2034         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
2035         buffer_format->cs.font = (buffer_format->font != current_format->font);
2036         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
2037         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2038
2039         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2040         if (buffer_format->cs.bold) {
2041                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2042                                               GINT_TO_POINTER (buffer_format->bold&0x1));
2043         }
2044         if (buffer_format->cs.italic) {
2045                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2046                                               GINT_TO_POINTER (buffer_format->italic&0x1));
2047         }
2048         if (buffer_format->cs.color) {
2049                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2050                                               GINT_TO_POINTER (&(buffer_format->color)));
2051         }
2052         if (buffer_format->cs.font_size) {
2053                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2054                                               GINT_TO_POINTER (buffer_format->font_size));
2055         }
2056         if (buffer_format->cs.justification) {
2057                 switch (buffer_format->justification) {
2058                 case GTK_JUSTIFY_LEFT:
2059                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2060                                                       GINT_TO_POINTER(TRUE));
2061                         break;
2062                 case GTK_JUSTIFY_CENTER:
2063                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2064                                                       GINT_TO_POINTER(TRUE));
2065                         break;
2066                 case GTK_JUSTIFY_RIGHT:
2067                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2068                                                       GINT_TO_POINTER(TRUE));
2069                         break;
2070                 default:
2071                         break;
2072                 }
2073                         
2074         }
2075         if (buffer_format->cs.font) {
2076                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2077                                               GINT_TO_POINTER (buffer_format->font));
2078         }
2079         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2080         if (buffer_format->cs.bullet) {
2081                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2082                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2083         }
2084 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2085         
2086         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2087         
2088         g_free (buffer_format);
2089         g_free (current_format);
2090
2091         /* Check dimming rules */
2092         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2093         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2094 }
2095
2096 static void
2097 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2098 {
2099         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2100         GtkAction *action;
2101         ModestWindowPrivate *parent_priv;
2102         ModestMsgEditWindowPrivate *priv;
2103         
2104         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2105         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2106
2107         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2108                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2109                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2110                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2111         } else {
2112                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2113                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2114                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2115         }
2116
2117         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2118
2119         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2120         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2121
2122         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2123         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2124
2125 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2126 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2127
2128         action = NULL;
2129         switch (buffer_format->justification)
2130         {
2131         case GTK_JUSTIFY_LEFT:
2132                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2133                 break;
2134         case GTK_JUSTIFY_CENTER:
2135                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2136                 break;
2137         case GTK_JUSTIFY_RIGHT:
2138                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2139                 break;
2140         default:
2141                 break;
2142         }
2143         
2144         if (action != NULL)
2145                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2146         
2147         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
2148                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
2149                                          window);
2150         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2151         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
2152                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
2153                                            window);
2154
2155         if (priv->current_size_index != buffer_format->font_size) {
2156                 GtkTreeIter iter;
2157                 GtkTreePath *path;
2158
2159                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2160                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2161                         gchar *size_text;
2162                         gchar *markup;
2163
2164                         priv->current_size_index = buffer_format->font_size;
2165
2166                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2167                         markup = g_strconcat ("<span font_family='Sans'>", 
2168                                               size_text, "</span>", NULL);
2169                         
2170                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2171                         g_free (markup);
2172                         g_free (size_text);
2173                 }
2174                 gtk_tree_path_free (path);              
2175         }
2176
2177         if (priv->current_face_index != buffer_format->font) {
2178                 GtkTreeIter iter;
2179                 GtkTreePath *path;
2180
2181                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2182                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2183                         gchar *face_name;
2184                         gchar *markup;
2185
2186                         priv->current_face_index = buffer_format->font;
2187                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2188                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2189                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2190                         g_free (face_name);
2191                         g_free (markup);
2192                 }
2193
2194         }
2195
2196         g_free (buffer_format);
2197
2198 }
2199
2200 #ifdef MODEST_HILDON_VERSION_0
2201 void
2202 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2203 {
2204         
2205         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2206         ModestMsgEditWindowPrivate *priv;
2207         GtkWidget *dialog = NULL;
2208         gint response;
2209         GdkColor *new_color = NULL;
2210
2211         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2212         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2213         
2214         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2215         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2216         g_free (buffer_format);
2217
2218         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2219                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2220                 if (new_color != NULL) {
2221                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2222                                                       (gpointer) new_color);
2223                 }
2224         }
2225         gtk_widget_destroy (dialog);
2226 }
2227
2228
2229 void
2230 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2231 {
2232         
2233         ModestMsgEditWindowPrivate *priv;
2234         GtkWidget *dialog = NULL;
2235         gint response;
2236         GdkColor *old_color = NULL;
2237         const GdkColor *new_color = NULL;
2238         
2239         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2240         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2241         
2242         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2243         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2244
2245         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2246                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2247                 if (new_color != NULL)
2248                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2249         }
2250         gtk_widget_destroy (dialog);
2251
2252 }
2253
2254 #else 
2255 void
2256 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2257 {
2258         
2259         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2260         ModestMsgEditWindowPrivate *priv;
2261         GtkWidget *dialog = NULL;
2262
2263         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2264         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2265                 
2266         dialog = hildon_color_chooser_new ();
2267         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2268         g_free (buffer_format);
2269
2270         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2271                 GdkColor col;
2272                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2273                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2274                                               (gpointer) &col);
2275         }
2276         gtk_widget_destroy (dialog);
2277 }
2278
2279
2280 void
2281 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2282 {
2283         
2284         ModestMsgEditWindowPrivate *priv;
2285         GtkWidget *dialog = NULL;
2286         GdkColor *old_color = NULL;
2287         
2288         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2289         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2290         
2291         dialog = hildon_color_chooser_new ();
2292         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2293
2294         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2295                 GdkColor col;
2296                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2297                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2298         }
2299         gtk_widget_destroy (dialog);
2300 }
2301
2302 #endif /*!MODEST_HILDON_VERSION_0*/
2303
2304
2305
2306 static TnyStream*
2307 create_stream_for_uri (const gchar* uri)
2308 {
2309         if (!uri)
2310                 return NULL;
2311                 
2312         TnyStream *result = NULL;
2313
2314         GnomeVFSHandle *handle = NULL;
2315         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2316         if (test == GNOME_VFS_OK) {
2317                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2318                 /* Streams over OBEX (Bluetooth) are not seekable but
2319                  * we expect them to be (we might need to read them
2320                  * several times). So if this is a Bluetooth URI just
2321                  * read the whole file into memory (this is not a fast
2322                  * protocol so we can assume that these files are not
2323                  * going to be very big) */
2324                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2325                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2326                         TnyStream *memstream = tny_camel_mem_stream_new ();
2327                         tny_stream_write_to_stream (vfssstream, memstream);
2328                         g_object_unref (vfssstream);
2329                         result = memstream;
2330                 } else {
2331                         result = vfssstream;
2332                 }
2333         }
2334         
2335         return result;
2336 }
2337
2338 void
2339 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2340 {
2341         
2342         ModestMsgEditWindowPrivate *priv;
2343         GtkWidget *dialog = NULL;
2344         gint response = 0;
2345         GSList *uris = NULL;
2346         GSList *uri_node = NULL;
2347
2348         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2349
2350         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2351         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2352         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2353
2354         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2355
2356         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2357                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2358
2359         response = gtk_dialog_run (GTK_DIALOG (dialog));
2360         switch (response) {
2361         case GTK_RESPONSE_OK:
2362         {
2363                 gchar *current_folder;
2364                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2365                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2366                 if (current_folder && current_folder != '\0') {
2367                         GError *err = NULL;
2368                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH, 
2369                                                 current_folder, &err);
2370                         if (err != NULL) {
2371                                 g_debug ("Error storing latest used folder: %s", err->message);
2372                                 g_error_free (err);
2373                         }
2374                 }
2375                 g_free (current_folder);
2376         }
2377         break;
2378         default:
2379                 break;
2380         }
2381         gtk_widget_destroy (dialog);
2382
2383         g_object_ref (window);
2384         /* The operation could take some time so allow the dialog to be closed */
2385         while (gtk_events_pending ())
2386                 gtk_main_iteration ();
2387
2388         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2389                 const gchar *uri;
2390                 GnomeVFSHandle *handle = NULL;
2391                 GnomeVFSResult result;
2392                 GtkTextIter position;
2393                 GtkTextMark *insert_mark;
2394
2395                 uri = (const gchar *) uri_node->data;
2396                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2397                 if (result == GNOME_VFS_OK) {
2398                         GdkPixbuf *pixbuf;
2399                         GnomeVFSFileInfo *info;
2400                         gchar *filename, *basename, *escaped_filename;
2401                         TnyMimePart *mime_part;
2402                         gchar *content_id;
2403                         const gchar *mime_type = NULL;
2404                         GnomeVFSURI *vfs_uri;
2405                         guint64 stream_size;
2406
2407                         gnome_vfs_close (handle);
2408                         vfs_uri = gnome_vfs_uri_new (uri);
2409
2410                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2411                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2412                         g_free (escaped_filename);
2413                         gnome_vfs_uri_unref (vfs_uri);
2414                         info = gnome_vfs_file_info_new ();
2415
2416                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2417                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2418                             == GNOME_VFS_OK)
2419                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2420
2421                         mime_part = tny_platform_factory_new_mime_part
2422                                 (modest_runtime_get_platform_factory ());
2423
2424                         TnyStream *stream = create_stream_for_uri (uri);
2425
2426                         if (stream == NULL) {
2427
2428                                 modest_platform_information_banner (NULL, NULL, 
2429                                                                     _FM("sfil_ib_opening_not_allowed"));
2430                                 g_free (filename);
2431                                 g_object_unref (mime_part);
2432                                 gnome_vfs_file_info_unref (info);
2433                                 continue;
2434                         }
2435
2436                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2437
2438                         content_id = g_strdup_printf ("%d", priv->next_cid);
2439                         tny_mime_part_set_content_id (mime_part, content_id);
2440                         g_free (content_id);
2441                         priv->next_cid++;
2442
2443                         basename = g_path_get_basename (filename);
2444                         tny_mime_part_set_filename (mime_part, basename);
2445                         g_free (basename);
2446
2447                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2448
2449                         if (pixbuf != NULL) {
2450                                 priv->images_size += stream_size;
2451                                 priv->images_count ++;
2452                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2453                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2454                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, 
2455                                                              tny_mime_part_get_content_id (mime_part), pixbuf);
2456                                 g_object_unref (pixbuf);
2457
2458                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2459                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2460                         } else {
2461                                 modest_platform_information_banner (NULL, NULL,
2462                                                                     _("mail_ib_file_operation_failed"));
2463                         }
2464
2465                         g_free (filename);
2466                         g_object_unref (mime_part);
2467                         gnome_vfs_file_info_unref (info);
2468
2469                 }
2470         }
2471         g_object_unref (window);
2472 }
2473
2474 static void
2475 on_attach_file_response (GtkDialog *dialog,
2476                          gint       arg1,
2477                          gpointer   user_data)
2478 {
2479         GSList *uris = NULL;
2480         GSList *uri_node;
2481         GnomeVFSFileSize total_size, allowed_size;
2482         ModestMsgEditWindow *window;
2483         ModestMsgEditWindowPrivate *priv;
2484         gint att_num;
2485         guint64 att_size;
2486
2487         switch (arg1) {
2488         case GTK_RESPONSE_OK:
2489         {
2490                 gchar *current_folder;
2491
2492                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2493                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2494                 if (current_folder && current_folder != '\0') {
2495                         GError *err = NULL;
2496                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, 
2497                                                 current_folder, &err);
2498                         if (err != NULL) {
2499                                 g_debug ("Error storing latest used folder: %s", err->message);
2500                                 g_error_free (err);
2501                         }
2502                 }
2503                 g_free (current_folder);
2504         }
2505         break;
2506         default:
2507                 break;
2508         }
2509
2510         window = MODEST_MSG_EDIT_WINDOW (user_data);
2511         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2512
2513         /* allowed size is the maximum size - what's already there */
2514         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2515                                            &att_num, &att_size);
2516         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2517
2518         total_size = 0;
2519         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2520
2521                 const gchar *uri = (const gchar *) uri_node->data;
2522
2523                 total_size += 
2524                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2525
2526                 if (total_size > allowed_size) {
2527                         g_debug ("%s: total size: %u", 
2528                                    __FUNCTION__, (unsigned int)total_size);
2529                         break;
2530                 }
2531                 allowed_size -= total_size;
2532         }
2533         g_slist_foreach (uris, (GFunc) g_free, NULL);
2534         g_slist_free (uris);
2535
2536         gtk_widget_destroy (GTK_WIDGET (dialog));
2537 }
2538
2539 void
2540 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2541 {
2542         GtkWidget *dialog = NULL;
2543         ModestMsgEditWindowPrivate *priv;
2544         gchar *conf_folder;
2545
2546         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2547
2548         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2549
2550         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2551                 return;
2552
2553         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2554                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2555         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2556         conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
2557                                               MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2558         if (conf_folder && conf_folder[0] != '\0') {
2559                 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2560         } else {
2561                 gchar *docs_folder;
2562                 /* Set the default folder to documents folder */
2563                 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
2564                 if (!docs_folder) {
2565                         /* fallback */
2566                         docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2567                                                         ".documents", NULL);
2568                 }
2569                 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2570                 g_free (docs_folder);
2571         }
2572         g_free (conf_folder);
2573         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2574         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2575                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2576
2577         /* Connect to response & show */
2578         g_signal_connect (dialog, "response", 
2579                           G_CALLBACK (on_attach_file_response), window);
2580         gtk_widget_show (dialog);
2581 }
2582
2583
2584 GnomeVFSFileSize
2585 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2586                                         const gchar *uri, 
2587                                         GnomeVFSFileSize allowed_size)
2588
2589 {
2590         GnomeVFSHandle *handle = NULL;
2591         ModestMsgEditWindowPrivate *priv;
2592         GnomeVFSResult result;
2593         GnomeVFSFileSize size = 0;
2594         g_return_val_if_fail (window, 0);
2595         g_return_val_if_fail (uri, 0);
2596
2597         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2598
2599         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2600         if (result == GNOME_VFS_OK) {
2601                 TnyMimePart *mime_part;
2602                 TnyStream *stream;
2603                 const gchar *mime_type = NULL;
2604                 gchar *basename;
2605                 gchar *escaped_filename;
2606                 gchar *filename;
2607                 gchar *content_id;
2608                 GnomeVFSFileInfo *info;
2609                 GnomeVFSURI *vfs_uri;
2610
2611                 gnome_vfs_close (handle);
2612                 vfs_uri = gnome_vfs_uri_new (uri);
2613                 
2614
2615                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2616                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2617                 g_free (escaped_filename);
2618                 gnome_vfs_uri_unref (vfs_uri);
2619
2620                 info = gnome_vfs_file_info_new ();
2621                 
2622                 if (gnome_vfs_get_file_info (uri, 
2623                                              info, 
2624                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2625                     == GNOME_VFS_OK)
2626                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2627                 mime_part = tny_platform_factory_new_mime_part
2628                         (modest_runtime_get_platform_factory ());
2629                 
2630                 /* try to get the attachment's size; this may fail for weird
2631                  * file systems, like obex, upnp... */
2632                 if (allowed_size != 0 &&
2633                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2634                         size = info->size;
2635                         if (size > allowed_size) {
2636                                 modest_platform_information_banner (NULL, NULL,
2637                                                                     _("mail_ib_error_attachment_size"));
2638                                 g_free (filename);
2639                                 return 0;
2640                         }
2641                 } else
2642                         g_debug ("%s: could not get attachment size", __FUNCTION__);
2643                 
2644                 stream = create_stream_for_uri (uri);
2645                 
2646                 if (stream == NULL) {
2647
2648                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2649
2650                         g_object_unref (mime_part);
2651                         g_free (filename);
2652                         gnome_vfs_file_info_unref (info);
2653                         return 0;
2654                 }
2655
2656                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2657                 g_object_unref (stream);
2658                 
2659                 content_id = g_strdup_printf ("%d", priv->next_cid);
2660                 tny_mime_part_set_content_id (mime_part, content_id);
2661                 g_free (content_id);
2662                 priv->next_cid++;
2663                 
2664                 basename = g_path_get_basename (filename);
2665                 tny_mime_part_set_filename (mime_part, basename);
2666                 g_free (basename);
2667                 
2668                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2669                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2670                                                         mime_part,
2671                                                         info->size == 0, info->size);
2672                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2673                 gtk_widget_show_all (priv->attachments_caption);
2674                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2675                 g_free (filename);
2676                 g_object_unref (mime_part);
2677                 gnome_vfs_file_info_unref (info);
2678         }
2679
2680         return size;
2681 }
2682
2683 void
2684 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2685                                            TnyList *att_list)
2686 {
2687         ModestMsgEditWindowPrivate *priv;
2688         TnyIterator *iter;
2689
2690         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2691         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2692
2693         if (att_list == NULL) {
2694                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2695                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2696                         g_object_unref (att_list);
2697                         return;
2698                 }
2699         } else {
2700                 g_object_ref (att_list);
2701         }
2702
2703         if (tny_list_get_length (att_list) == 0) {
2704                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2705         } else {
2706                 gboolean dialog_response;
2707                 gchar *message = NULL;
2708                 gchar *filename = NULL;
2709
2710                 if (tny_list_get_length (att_list) == 1) {
2711                         TnyMimePart *part;
2712                         iter = tny_list_create_iterator (att_list);
2713                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2714                         g_object_unref (iter);
2715                         if (TNY_IS_MSG (part)) {
2716                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2717                                 if (header) {
2718                                         filename = tny_header_dup_subject (header);
2719                                         g_object_unref (header);
2720                                 }
2721                                 if (filename == NULL) {
2722                                         filename = g_strdup (_("mail_va_no_subject"));
2723                                 }
2724                         } else {
2725                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2726                         }
2727                         g_object_unref (part);
2728                 } else {
2729                         filename = g_strdup ("");
2730                 }
2731                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2732                                                     "emev_nc_delete_attachments",
2733                                                     tny_list_get_length (att_list)), filename);
2734                 g_free (filename);
2735
2736                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2737                                                                            message);
2738                 g_free (message);
2739
2740                 if (dialog_response != GTK_RESPONSE_OK) {
2741                         g_object_unref (att_list);
2742                         return;
2743                 }
2744
2745                 for (iter = tny_list_create_iterator (att_list);
2746                      !tny_iterator_is_done (iter);
2747                      tny_iterator_next (iter)) {
2748                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2749                         const gchar *att_id;
2750                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2751
2752                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2753                                                                    mime_part);
2754                         if (tny_list_get_length (priv->attachments) == 0)
2755                                 gtk_widget_hide (priv->attachments_caption);
2756                         att_id = tny_mime_part_get_content_id (mime_part);
2757                         if (att_id != NULL)
2758                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2759                                                                  att_id);
2760                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2761                         g_object_unref (mime_part);
2762                 }
2763                 g_object_unref (iter);
2764         }
2765
2766         g_object_unref (att_list);
2767
2768         /* if the last attachment has been removed, focus the Subject: field */
2769         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2770                 gtk_widget_grab_focus (priv->subject_field);
2771 }
2772
2773 static void
2774 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2775                                             gpointer userdata)
2776 {
2777         ModestMsgEditWindowPrivate *priv;
2778         GdkColor *new_color;
2779         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2780         
2781 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2782         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2783 #else 
2784         GdkColor col;
2785         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2786         new_color = &col;
2787 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2788
2789         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2790         
2791         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2792
2793 }
2794
2795 static void
2796 font_size_clicked (GtkToolButton *button,
2797                    ModestMsgEditWindow *window)
2798 {
2799         ModestMsgEditWindowPrivate *priv;
2800         GtkWidget *selector, *dialog;
2801         
2802         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2803
2804         selector = hildon_touch_selector_new ();
2805         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2806         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2807
2808         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2809         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2810         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2811
2812         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2813                 gint new_index;
2814                 gchar *size_text;
2815                 gchar *markup;
2816                 WPTextBufferFormat format;
2817
2818                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2819
2820                 memset (&format, 0, sizeof (format));
2821                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2822
2823                 format.cs.font_size = TRUE;
2824                 format.cs.text_position = TRUE;
2825                 format.cs.font = TRUE;
2826                 format.font_size = new_index;
2827 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2828
2829                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2830                                                    GINT_TO_POINTER (new_index)))
2831                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2832                 
2833                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2834                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2835                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2836                                       size_text, "</span>", NULL);
2837                 g_free (size_text);
2838                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2839                 g_free (markup);
2840
2841         }
2842         gtk_widget_destroy (dialog);
2843
2844         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2845
2846 }
2847
2848 static void
2849 font_face_clicked (GtkToolButton *button,
2850                    ModestMsgEditWindow *window)
2851 {
2852         ModestMsgEditWindowPrivate *priv;
2853         GtkWidget *selector, *dialog;
2854         GtkCellRenderer *renderer;
2855         
2856         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2857
2858         selector = hildon_touch_selector_new ();
2859         renderer = gtk_cell_renderer_text_new ();
2860         g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2861         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2862                                              renderer, "family", 0, "text", 0, NULL);
2863         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2864
2865         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2866         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2867         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2868
2869         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2870                 gint new_font_index;
2871                 GtkTreePath *path;
2872                 GtkTreeIter iter;
2873
2874                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2875                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2876                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2877                         gchar *face_name;
2878                         gchar *markup;
2879
2880                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2881
2882                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2883                                                            GINT_TO_POINTER(new_font_index)))
2884                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2885
2886                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2887                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2888
2889                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2890                         g_free (face_name);
2891                         g_free (markup);
2892                 }
2893                 gtk_tree_path_free (path);
2894
2895         }
2896         gtk_widget_destroy (dialog);
2897
2898         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2899
2900 }
2901
2902 void
2903 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2904                                 gboolean show)
2905 {
2906         ModestMsgEditWindowPrivate *priv = NULL;
2907         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2908
2909         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2910         if (!priv->update_caption_visibility)
2911                 return;
2912
2913         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2914         if (show)
2915                 gtk_widget_show (priv->cc_caption);
2916         else
2917                 gtk_widget_hide (priv->cc_caption);
2918
2919         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2920 }
2921
2922 void
2923 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2924                                  gboolean show)
2925 {
2926         ModestMsgEditWindowPrivate *priv = NULL;
2927         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2928
2929         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2930         if (!priv->update_caption_visibility)
2931                 return;
2932
2933         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2934         if (show)
2935                 gtk_widget_show (priv->bcc_caption);
2936         else
2937                 gtk_widget_hide (priv->bcc_caption);
2938
2939         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2940 }
2941
2942 static void
2943 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2944                                          ModestRecptEditor *editor)
2945 {
2946         ModestMsgEditWindowPrivate *priv;
2947
2948         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2949         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2950         
2951         /* we check for low-mem; in that case, show a warning, and don't allow
2952          * for the addressbook
2953          */
2954         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2955                 return;
2956
2957         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2958
2959         if (editor == NULL) {
2960                 GtkWidget *view_focus, *parent;
2961                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2962
2963                 /* This code should be kept in sync with ModestRecptEditor. The
2964                    textview inside the recpt editor is the one that really gets the
2965                    focus. As it's inside a scrolled window, and this one inside the
2966                    hbox recpt editor inherits from, we'll need to go up in the 
2967                    hierarchy to know if the text view is part of the recpt editor
2968                    or if it's a different text entry */
2969                 parent = gtk_widget_get_parent (view_focus);
2970                 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2971                         editor = MODEST_RECPT_EDITOR (parent);
2972
2973                 if (editor == NULL)
2974                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2975         }
2976
2977         modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2978 }
2979
2980 void
2981 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2982 {
2983         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2984
2985         modest_msg_edit_window_open_addressbook (window, NULL);
2986 }
2987
2988 static void
2989 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2990                                      gboolean show_toolbar)
2991 {
2992         ModestWindowPrivate *parent_priv;
2993         ModestMsgEditWindowPrivate *priv;
2994
2995         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2996         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2997         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2998
2999         /* We can not just use the code of
3000            modest_msg_edit_window_setup_toolbar because it has a
3001            mixture of both initialization and creation code. */
3002         if (show_toolbar) {
3003                 gint current_format;
3004                 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3005                         ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3006                 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3007                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3008                 } else {
3009                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
3010                 }
3011         } else {
3012                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
3013         }
3014 }
3015
3016 void
3017 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
3018                                            TnyHeaderFlags priority_flags)
3019 {
3020         ModestMsgEditWindowPrivate *priv;
3021         ModestWindowPrivate *parent_priv;
3022
3023         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3024
3025         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3026         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3027
3028         if (priv->priority_flags != priority_flags) {
3029                 GtkAction *priority_action = NULL;
3030
3031                 priv->priority_flags = priority_flags;
3032
3033                 switch (priority_flags) {
3034                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
3035                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3036                                                       MODEST_HEADER_ICON_HIGH, 
3037                                                       HILDON_ICON_SIZE_SMALL);
3038                         gtk_widget_show (priv->priority_icon);
3039                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3040                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
3041                         break;
3042                 case TNY_HEADER_FLAG_LOW_PRIORITY:
3043                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3044                                                       MODEST_HEADER_ICON_LOW,
3045                                                       HILDON_ICON_SIZE_SMALL);
3046                         gtk_widget_show (priv->priority_icon);
3047                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3048                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3049                         break;
3050                 default:
3051                         gtk_widget_hide (priv->priority_icon);
3052                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3053                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3054                         break;
3055                 }
3056                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3057                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3058         }
3059         gtk_widget_queue_resize (priv->subject_box);
3060 }
3061
3062 void
3063 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3064                                         gint file_format)
3065 {
3066         ModestMsgEditWindowPrivate *priv;
3067         ModestWindowPrivate *parent_priv;
3068         gint current_format;
3069
3070         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3071
3072         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3073         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3074
3075         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3076                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3077
3078         gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3079
3080         if (current_format != file_format) {
3081                 switch (file_format) {
3082                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3083                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3084                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3085                         if (parent_priv->toolbar)
3086                                 gtk_widget_show (parent_priv->toolbar);
3087                         break;
3088                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3089                 {
3090                         GtkWidget *dialog;
3091                         gint response;
3092                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3093                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3094                         gtk_widget_destroy (dialog);
3095                         if (response == GTK_RESPONSE_OK) {
3096                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3097                                 if (parent_priv->toolbar)
3098                                         gtk_widget_hide (parent_priv->toolbar);
3099            &