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