a286d1ed95b0b0a11b7a49bfeddb1920c9694a41
[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/ToolbarSend");
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/ActionsBold");
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         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1559         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1560         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1561
1562         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1563            will not show the tool items added to the placeholders) */
1564         gtk_widget_show_all (parent_priv->toolbar);
1565
1566         /* Set the no show all *after* showing all items. We do not
1567            want the toolbar to be shown with a show all because it
1568            could go agains the gconf setting regarding showing or not
1569            the toolbar of the editor window */
1570         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1571 }
1572
1573
1574
1575 ModestWindow*
1576 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, const gchar *mailbox, gboolean preserve_is_rich)
1577 {
1578         GObject *obj;
1579         ModestWindowPrivate *parent_priv;
1580         ModestMsgEditWindowPrivate *priv;
1581         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1582         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1583         ModestWindowMgr *mgr = NULL;
1584
1585         g_return_val_if_fail (msg, NULL);
1586         g_return_val_if_fail (account_name, NULL);
1587
1588         mgr = modest_runtime_get_window_mgr ();
1589         
1590         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1591
1592         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1593         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1594
1595         /* Menubar. Update the state of some toggles */
1596         priv->from_field_protos = get_transports ();
1597         priv->original_mailbox = NULL;
1598         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1599         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1600         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1601         if (mailbox && modest_pair_list_find_by_first_as_string (priv->from_field_protos, mailbox)) {
1602                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) mailbox);
1603                 priv->original_mailbox = g_strdup (mailbox);
1604         } else if (modest_account_mgr_account_is_multimailbox (modest_runtime_get_account_mgr (), account_name, NULL)) {
1605                 /* We set the first mailbox as the active mailbox */
1606                 priv->original_mailbox = multimailbox_get_default_mailbox (account_name);
1607                 if (priv->original_mailbox != NULL)
1608                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1609                                                               (gpointer) priv->original_mailbox);
1610                 else
1611                         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field),
1612                                                               (gpointer) account_name);
1613         } else {
1614                 modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1615         }
1616         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1617         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1618                                  _("mail_va_from"));
1619         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1620                                  hildon_touch_selector_get_current_text 
1621                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1622         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1623         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1624
1625         /* Init window */
1626         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1627
1628         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1629                 
1630         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1631         modest_window_set_active_mailbox (MODEST_WINDOW(obj), priv->original_mailbox);
1632
1633         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1634
1635         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1636         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1637         /* Add common dimming rules */
1638         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1639                                               modest_msg_edit_window_toolbar_dimming_entries,
1640                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1641                                               MODEST_WINDOW (obj));
1642         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_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_size_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->font_face_toolitem,
1649                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1650                                                     MODEST_WINDOW (obj));
1651         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->send_button,
1652                                                     G_CALLBACK (modest_ui_dimming_rules_on_send),
1653                                                     MODEST_WINDOW (obj));
1654         /* Insert dimming rules group for this window */
1655         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1656         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1657
1658         /* Setup app menu */
1659         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1660
1661         /* Checks the dimming rules */
1662         g_object_unref (toolbar_rules_group);
1663         g_object_unref (clipboard_rules_group);
1664         gtk_widget_hide (priv->priority_icon);
1665         gtk_widget_queue_resize (priv->subject_box);
1666         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1667
1668         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1669
1670         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1671         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1672         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1673         priv->update_caption_visibility = TRUE;
1674
1675         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1676
1677         /* Track account-removed signal, this window should be closed
1678            in the case we're creating a mail associated to the account
1679            that is deleted */
1680         priv->account_removed_handler_id = 
1681                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1682                                   "account_removed",
1683                                   G_CALLBACK(on_account_removed),
1684                                   obj);
1685
1686         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1687
1688         return (ModestWindow*) obj;
1689 }
1690
1691 static gint
1692 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1693 {
1694         GString **string_buffer = (GString **) user_data;
1695
1696         *string_buffer = g_string_append (*string_buffer, buffer);
1697    
1698         return 0;
1699 }
1700
1701 /**
1702  * @result: A new string which should be freed with g_free().
1703  */
1704 static gchar *
1705 get_formatted_data (ModestMsgEditWindow *edit_window)
1706 {
1707         ModestMsgEditWindowPrivate *priv;
1708         GString *string_buffer = g_string_new ("");
1709         
1710         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1711
1712         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1713
1714         modest_text_utils_hyperlinkify (string_buffer);
1715
1716         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1717
1718         return g_string_free (string_buffer, FALSE);
1719                                                                         
1720 }
1721
1722 MsgData * 
1723 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1724 {
1725         MsgData *data;
1726         const gchar *account_name;
1727         ModestMsgEditWindowPrivate *priv;
1728         TnyIterator *att_iter;
1729         const gchar *picker_active_id;
1730         
1731         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1732
1733         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1734         
1735         picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1736         g_return_val_if_fail (picker_active_id, NULL);
1737         account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1738         
1739         /* don't free these (except from) */
1740         data = g_slice_new0 (MsgData);
1741         data->from    =  g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1742         data->account_name = g_strdup (account_name);
1743         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1744         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1745         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1746         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1747         data->references = g_strdup (priv->references);
1748         data->in_reply_to = g_strdup (priv->in_reply_to);
1749         if (priv->draft_msg) {
1750                 data->draft_msg = g_object_ref (priv->draft_msg);
1751         } else if (priv->outbox_msg) {
1752                 data->draft_msg = g_object_ref (priv->outbox_msg);
1753         } else {
1754                 data->draft_msg = NULL;
1755         }
1756
1757         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1758         GtkTextIter b, e;
1759         gtk_text_buffer_get_bounds (buf, &b, &e);
1760         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1761
1762         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1763                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1764         else
1765                 data->html_body = NULL;
1766
1767         /* deep-copy the data */
1768         att_iter = tny_list_create_iterator (priv->attachments);
1769         data->attachments = NULL;
1770         while (!tny_iterator_is_done (att_iter)) {
1771                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1772                 if (!(TNY_IS_MIME_PART(part))) {
1773                         g_warning ("strange data in attachment list");
1774                         g_object_unref (part);
1775                         tny_iterator_next (att_iter);
1776                         continue;
1777                 }
1778                 data->attachments = g_list_append (data->attachments,
1779                                                    part);
1780                 tny_iterator_next (att_iter);
1781         }
1782         g_object_unref (att_iter);
1783
1784         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1785         att_iter = tny_list_create_iterator (priv->images);
1786         data->images = NULL;
1787         while (!tny_iterator_is_done (att_iter)) {
1788                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1789                 const gchar *cid;
1790                 if (!(TNY_IS_MIME_PART(part))) {
1791                         g_warning ("strange data in attachment list");
1792                         g_object_unref (part);
1793                         tny_iterator_next (att_iter);
1794                         continue;
1795                 }
1796                 cid = tny_mime_part_get_content_id (part);
1797                 if (cid) {                      
1798                         gchar *image_tag_id;
1799                         GtkTextTag *image_tag;
1800                         GtkTextIter iter;
1801                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1802                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1803                         g_free (image_tag_id);
1804                         
1805                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1806                         if (image_tag && 
1807                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1808                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1809                                 data->images = g_list_append (data->images,
1810                                                               g_object_ref (part));
1811                 }
1812                 g_object_unref (part);
1813                 tny_iterator_next (att_iter);
1814         }
1815         g_object_unref (att_iter);
1816         
1817         data->priority_flags = priv->priority_flags;
1818
1819         return data;
1820 }
1821
1822
1823 static void
1824 unref_gobject (GObject *obj, gpointer data)
1825 {
1826         if (!G_IS_OBJECT(obj))
1827                 return;
1828         g_object_unref (obj);
1829 }
1830
1831 void 
1832 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1833                                                       MsgData *data)
1834 {
1835         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1836
1837         if (!data)
1838                 return;
1839
1840         g_free (data->to);
1841         g_free (data->cc);
1842         g_free (data->bcc);
1843         g_free (data->from);
1844         g_free (data->subject);
1845         g_free (data->plain_body);
1846         g_free (data->html_body);
1847         g_free (data->account_name);
1848         g_free (data->references);
1849         g_free (data->in_reply_to);
1850         
1851         if (data->draft_msg != NULL) {
1852                 g_object_unref (data->draft_msg);
1853                 data->draft_msg = NULL;
1854         }
1855         
1856         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1857         g_list_free (data->attachments);
1858         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1859         g_list_free (data->images);
1860         
1861         g_slice_free (MsgData, data);
1862 }
1863
1864 void                    
1865 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1866                                        gint *parts_count,
1867                                        guint64 *parts_size)
1868 {
1869         ModestMsgEditWindowPrivate *priv;
1870
1871         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1872
1873         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1874
1875         /* TODO: add images */
1876         *parts_size += priv->images_size;
1877         *parts_count += priv->images_count;
1878
1879 }
1880
1881 ModestMsgEditFormat
1882 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1883 {
1884         gboolean rich_text;
1885         ModestMsgEditWindowPrivate *priv = NULL;
1886         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1887
1888         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1889
1890         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1891         if (rich_text)
1892                 return MODEST_MSG_EDIT_FORMAT_HTML;
1893         else
1894                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1895 }
1896
1897 void
1898 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1899                                    ModestMsgEditFormat format)
1900 {
1901         ModestMsgEditWindowPrivate *priv;
1902         ModestWindowPrivate *parent_priv;
1903
1904         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1905         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1906         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1907
1908         switch (format) {
1909         case MODEST_MSG_EDIT_FORMAT_HTML:
1910                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1911                 if (parent_priv->toolbar) gtk_widget_show (parent_priv->toolbar);
1912                 break;
1913         case MODEST_MSG_EDIT_FORMAT_TEXT:
1914                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1915                 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
1916                 break;
1917         default:
1918                 g_return_if_reached ();
1919         }
1920 }
1921
1922 ModestMsgEditFormatState *
1923 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1924 {
1925         ModestMsgEditFormatState *format_state = NULL;
1926         ModestMsgEditWindowPrivate *priv;
1927         WPTextBufferFormat *buffer_format;
1928
1929         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1930
1931         buffer_format = g_new0 (WPTextBufferFormat, 1);
1932         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1933
1934         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1935
1936         format_state = g_new0 (ModestMsgEditFormatState, 1);
1937         format_state->bold = buffer_format->bold&0x1;
1938         format_state->italics = buffer_format->italic&0x1;
1939         format_state->bullet = buffer_format->bullet&0x1;
1940         format_state->color = buffer_format->color;
1941         format_state->font_size = buffer_format->font_size;
1942         format_state->font_family = wp_get_font_name (buffer_format->font);
1943         format_state->justification = buffer_format->justification;
1944         g_free (buffer_format);
1945
1946         return format_state;
1947  
1948 }
1949
1950 void
1951 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1952                                          const ModestMsgEditFormatState *format_state)
1953 {
1954         ModestMsgEditWindowPrivate *priv;
1955         WPTextBufferFormat *buffer_format;
1956         WPTextBufferFormat *current_format;
1957
1958         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1959         g_return_if_fail (format_state != NULL);
1960
1961         buffer_format = g_new0 (WPTextBufferFormat, 1);
1962         current_format = g_new0 (WPTextBufferFormat, 1);
1963
1964         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1965         gtk_widget_grab_focus (priv->msg_body);
1966         buffer_format->bold = (format_state->bold != FALSE);
1967         buffer_format->italic = (format_state->italics != FALSE);
1968         buffer_format->color = format_state->color;
1969         buffer_format->font_size = format_state->font_size;
1970         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1971         buffer_format->justification = format_state->justification;
1972         buffer_format->bullet = format_state->bullet;
1973
1974         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1975
1976         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1977         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1978         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1979         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1980         buffer_format->cs.font = (buffer_format->font != current_format->font);
1981         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1982         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1983
1984         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1985         if (buffer_format->cs.bold) {
1986                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1987                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1988         }
1989         if (buffer_format->cs.italic) {
1990                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1991                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1992         }
1993         if (buffer_format->cs.color) {
1994                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1995                                               GINT_TO_POINTER (&(buffer_format->color)));
1996         }
1997         if (buffer_format->cs.font_size) {
1998                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1999                                               GINT_TO_POINTER (buffer_format->font_size));
2000         }
2001         if (buffer_format->cs.justification) {
2002                 switch (buffer_format->justification) {
2003                 case GTK_JUSTIFY_LEFT:
2004                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2005                                                       GINT_TO_POINTER(TRUE));
2006                         break;
2007                 case GTK_JUSTIFY_CENTER:
2008                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2009                                                       GINT_TO_POINTER(TRUE));
2010                         break;
2011                 case GTK_JUSTIFY_RIGHT:
2012                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2013                                                       GINT_TO_POINTER(TRUE));
2014                         break;
2015                 default:
2016                         break;
2017                 }
2018                         
2019         }
2020         if (buffer_format->cs.font) {
2021                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2022                                               GINT_TO_POINTER (buffer_format->font));
2023         }
2024         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2025         if (buffer_format->cs.bullet) {
2026                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2027                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2028         }
2029 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2030         
2031         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2032         
2033         g_free (buffer_format);
2034         g_free (current_format);
2035
2036         /* Check dimming rules */
2037         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2038         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2039 }
2040
2041 static void
2042 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2043 {
2044         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2045         GtkAction *action;
2046         ModestWindowPrivate *parent_priv;
2047         ModestMsgEditWindowPrivate *priv;
2048         
2049         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2050         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2051
2052         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2053                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2054                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2055                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2056         } else {
2057                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2058                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2059                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2060         }
2061
2062         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2063
2064         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2065         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2066
2067         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2068         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2069
2070 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2071 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2072
2073         action = NULL;
2074         switch (buffer_format->justification)
2075         {
2076         case GTK_JUSTIFY_LEFT:
2077                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2078                 break;
2079         case GTK_JUSTIFY_CENTER:
2080                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2081                 break;
2082         case GTK_JUSTIFY_RIGHT:
2083                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2084                 break;
2085         default:
2086                 break;
2087         }
2088         
2089         if (action != NULL)
2090                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2091         
2092         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
2093                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
2094                                          window);
2095         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2096         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
2097                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
2098                                            window);
2099
2100         if (priv->current_size_index != buffer_format->font_size) {
2101                 GtkTreeIter iter;
2102                 GtkTreePath *path;
2103
2104                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2105                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2106                         gchar *size_text;
2107                         gchar *markup;
2108
2109                         priv->current_size_index = buffer_format->font_size;
2110
2111                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2112                         markup = g_strconcat ("<span font_family='Sans'>", 
2113                                               size_text, "</span>", NULL);
2114                         
2115                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2116                         g_free (markup);
2117                         g_free (size_text);
2118                 }
2119                 gtk_tree_path_free (path);              
2120         }
2121
2122         if (priv->current_face_index != buffer_format->font) {
2123                 GtkTreeIter iter;
2124                 GtkTreePath *path;
2125
2126                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2127                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2128                         gchar *face_name;
2129                         gchar *markup;
2130
2131                         priv->current_face_index = buffer_format->font;
2132                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2133                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2134                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2135                         g_free (face_name);
2136                         g_free (markup);
2137                 }
2138
2139         }
2140
2141         g_free (buffer_format);
2142
2143 }
2144
2145 #ifdef MODEST_HILDON_VERSION_0
2146 void
2147 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2148 {
2149         
2150         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2151         ModestMsgEditWindowPrivate *priv;
2152         GtkWidget *dialog = NULL;
2153         gint response;
2154         GdkColor *new_color = NULL;
2155
2156         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2157         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2158         
2159         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2160         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2161         g_free (buffer_format);
2162
2163         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2164                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2165                 if (new_color != NULL) {
2166                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2167                                                       (gpointer) new_color);
2168                 }
2169         }
2170         gtk_widget_destroy (dialog);
2171 }
2172
2173
2174 void
2175 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2176 {
2177         
2178         ModestMsgEditWindowPrivate *priv;
2179         GtkWidget *dialog = NULL;
2180         gint response;
2181         GdkColor *old_color = NULL;
2182         const GdkColor *new_color = NULL;
2183         
2184         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2185         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2186         
2187         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2188         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2189
2190         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2191                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2192                 if (new_color != NULL)
2193                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2194         }
2195         gtk_widget_destroy (dialog);
2196
2197 }
2198
2199 #else 
2200 void
2201 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2202 {
2203         
2204         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2205         ModestMsgEditWindowPrivate *priv;
2206         GtkWidget *dialog = NULL;
2207
2208         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2209         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2210                 
2211         dialog = hildon_color_chooser_new ();
2212         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2213         g_free (buffer_format);
2214
2215         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2216                 GdkColor col;
2217                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2218                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2219                                               (gpointer) &col);
2220         }
2221         gtk_widget_destroy (dialog);
2222 }
2223
2224
2225 void
2226 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2227 {
2228         
2229         ModestMsgEditWindowPrivate *priv;
2230         GtkWidget *dialog = NULL;
2231         GdkColor *old_color = NULL;
2232         
2233         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2234         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2235         
2236         dialog = hildon_color_chooser_new ();
2237         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2238
2239         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2240                 GdkColor col;
2241                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2242                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2243         }
2244         gtk_widget_destroy (dialog);
2245 }
2246
2247 #endif /*!MODEST_HILDON_VERSION_0*/
2248
2249
2250
2251 static TnyStream*
2252 create_stream_for_uri (const gchar* uri)
2253 {
2254         if (!uri)
2255                 return NULL;
2256                 
2257         TnyStream *result = NULL;
2258
2259         GnomeVFSHandle *handle = NULL;
2260         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2261         if (test == GNOME_VFS_OK) {
2262                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2263                 /* Streams over OBEX (Bluetooth) are not seekable but
2264                  * we expect them to be (we might need to read them
2265                  * several times). So if this is a Bluetooth URI just
2266                  * read the whole file into memory (this is not a fast
2267                  * protocol so we can assume that these files are not
2268                  * going to be very big) */
2269                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2270                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2271                         TnyStream *memstream = tny_camel_mem_stream_new ();
2272                         tny_stream_write_to_stream (vfssstream, memstream);
2273                         g_object_unref (vfssstream);
2274                         result = memstream;
2275                 } else {
2276                         result = vfssstream;
2277                 }
2278         }
2279         
2280         return result;
2281 }
2282
2283 void
2284 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2285 {
2286         
2287         ModestMsgEditWindowPrivate *priv;
2288         GtkWidget *dialog = NULL;
2289         gint response = 0;
2290         GSList *uris = NULL;
2291         GSList *uri_node = NULL;
2292
2293         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2294
2295         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2296         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2297         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2298
2299         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2300
2301         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2302                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2303
2304         response = gtk_dialog_run (GTK_DIALOG (dialog));
2305         switch (response) {
2306         case GTK_RESPONSE_OK:
2307         {
2308                 gchar *current_folder;
2309                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2310                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2311                 if (current_folder && current_folder != '\0') {
2312                         GError *err = NULL;
2313                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH, 
2314                                                 current_folder, &err);
2315                         if (err != NULL) {
2316                                 g_debug ("Error storing latest used folder: %s", err->message);
2317                                 g_error_free (err);
2318                         }
2319                 }
2320                 g_free (current_folder);
2321         }
2322         break;
2323         default:
2324                 break;
2325         }
2326         gtk_widget_destroy (dialog);
2327
2328         g_object_ref (window);
2329         /* The operation could take some time so allow the dialog to be closed */
2330         while (gtk_events_pending ())
2331                 gtk_main_iteration ();
2332
2333         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2334                 const gchar *uri;
2335                 GnomeVFSHandle *handle = NULL;
2336                 GnomeVFSResult result;
2337                 GtkTextIter position;
2338                 GtkTextMark *insert_mark;
2339
2340                 uri = (const gchar *) uri_node->data;
2341                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2342                 if (result == GNOME_VFS_OK) {
2343                         GdkPixbuf *pixbuf;
2344                         GnomeVFSFileInfo *info;
2345                         gchar *filename, *basename, *escaped_filename;
2346                         TnyMimePart *mime_part;
2347                         gchar *content_id;
2348                         const gchar *mime_type = NULL;
2349                         GnomeVFSURI *vfs_uri;
2350                         guint64 stream_size;
2351
2352                         gnome_vfs_close (handle);
2353                         vfs_uri = gnome_vfs_uri_new (uri);
2354
2355                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2356                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2357                         g_free (escaped_filename);
2358                         gnome_vfs_uri_unref (vfs_uri);
2359                         info = gnome_vfs_file_info_new ();
2360
2361                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2362                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2363                             == GNOME_VFS_OK)
2364                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2365
2366                         mime_part = tny_platform_factory_new_mime_part
2367                                 (modest_runtime_get_platform_factory ());
2368
2369                         TnyStream *stream = create_stream_for_uri (uri);
2370
2371                         if (stream == NULL) {
2372
2373                                 modest_platform_information_banner (NULL, NULL, 
2374                                                                     _FM("sfil_ib_opening_not_allowed"));
2375                                 g_free (filename);
2376                                 g_object_unref (mime_part);
2377                                 gnome_vfs_file_info_unref (info);
2378                                 continue;
2379                         }
2380
2381                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2382
2383                         content_id = g_strdup_printf ("%d", priv->next_cid);
2384                         tny_mime_part_set_content_id (mime_part, content_id);
2385                         g_free (content_id);
2386                         priv->next_cid++;
2387
2388                         basename = g_path_get_basename (filename);
2389                         tny_mime_part_set_filename (mime_part, basename);
2390                         g_free (basename);
2391
2392                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2393
2394                         if (pixbuf != NULL) {
2395                                 priv->images_size += stream_size;
2396                                 priv->images_count ++;
2397                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2398                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2399                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, 
2400                                                              tny_mime_part_get_content_id (mime_part), pixbuf);
2401                                 g_object_unref (pixbuf);
2402
2403                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2404                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2405                         } else {
2406                                 modest_platform_information_banner (NULL, NULL,
2407                                                                     _("mail_ib_file_operation_failed"));
2408                         }
2409
2410                         g_free (filename);
2411                         g_object_unref (mime_part);
2412                         gnome_vfs_file_info_unref (info);
2413
2414                 }
2415         }
2416         g_object_unref (window);
2417 }
2418
2419 static void
2420 on_attach_file_response (GtkDialog *dialog,
2421                          gint       arg1,
2422                          gpointer   user_data)
2423 {
2424         GSList *uris = NULL;
2425         GSList *uri_node;
2426         GnomeVFSFileSize total_size, allowed_size;
2427         ModestMsgEditWindow *window;
2428         ModestMsgEditWindowPrivate *priv;
2429         gint att_num;
2430         guint64 att_size;
2431
2432         switch (arg1) {
2433         case GTK_RESPONSE_OK:
2434         {
2435                 gchar *current_folder;
2436
2437                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2438                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2439                 if (current_folder && current_folder != '\0') {
2440                         GError *err = NULL;
2441                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, 
2442                                                 current_folder, &err);
2443                         if (err != NULL) {
2444                                 g_debug ("Error storing latest used folder: %s", err->message);
2445                                 g_error_free (err);
2446                         }
2447                 }
2448                 g_free (current_folder);
2449         }
2450         break;
2451         default:
2452                 break;
2453         }
2454
2455         window = MODEST_MSG_EDIT_WINDOW (user_data);
2456         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2457
2458         /* allowed size is the maximum size - what's already there */
2459         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2460                                            &att_num, &att_size);
2461         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2462
2463         total_size = 0;
2464         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2465
2466                 const gchar *uri = (const gchar *) uri_node->data;
2467
2468                 total_size += 
2469                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2470
2471                 if (total_size > allowed_size) {
2472                         g_warning ("%s: total size: %u", 
2473                                    __FUNCTION__, (unsigned int)total_size);
2474                         break;
2475                 }
2476                 allowed_size -= total_size;
2477         }
2478         g_slist_foreach (uris, (GFunc) g_free, NULL);
2479         g_slist_free (uris);
2480
2481         gtk_widget_destroy (GTK_WIDGET (dialog));
2482 }
2483
2484 void
2485 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2486 {
2487         GtkWidget *dialog = NULL;
2488         ModestMsgEditWindowPrivate *priv;
2489         gchar *conf_folder;
2490
2491         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2492
2493         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2494
2495         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2496                 return;
2497
2498         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2499                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2500         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2501         conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2502         if (conf_folder && conf_folder[0] != '\0') {
2503                 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2504         } else {
2505                 gchar *docs_folder;
2506                 /* Set the default folder to images folder */
2507                 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2508                                                 ".documents", NULL);
2509                 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2510                 g_free (docs_folder);
2511         }
2512         g_free (conf_folder);
2513         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2514         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2515                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2516
2517         /* Connect to response & show */
2518         g_signal_connect (dialog, "response", 
2519                           G_CALLBACK (on_attach_file_response), window);
2520         gtk_widget_show (dialog);
2521 }
2522
2523
2524 GnomeVFSFileSize
2525 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2526                                         const gchar *uri, 
2527                                         GnomeVFSFileSize allowed_size)
2528
2529 {
2530         GnomeVFSHandle *handle = NULL;
2531         ModestMsgEditWindowPrivate *priv;
2532         GnomeVFSResult result;
2533         GnomeVFSFileSize size = 0;
2534         g_return_val_if_fail (window, 0);
2535         g_return_val_if_fail (uri, 0);
2536
2537         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2538
2539         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2540         if (result == GNOME_VFS_OK) {
2541                 TnyMimePart *mime_part;
2542                 TnyStream *stream;
2543                 const gchar *mime_type = NULL;
2544                 gchar *basename;
2545                 gchar *escaped_filename;
2546                 gchar *filename;
2547                 gchar *content_id;
2548                 GnomeVFSFileInfo *info;
2549                 GnomeVFSURI *vfs_uri;
2550
2551                 gnome_vfs_close (handle);
2552                 vfs_uri = gnome_vfs_uri_new (uri);
2553                 
2554
2555                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2556                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2557                 g_free (escaped_filename);
2558                 gnome_vfs_uri_unref (vfs_uri);
2559
2560                 info = gnome_vfs_file_info_new ();
2561                 
2562                 if (gnome_vfs_get_file_info (uri, 
2563                                              info, 
2564                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2565                     == GNOME_VFS_OK)
2566                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2567                 mime_part = tny_platform_factory_new_mime_part
2568                         (modest_runtime_get_platform_factory ());
2569                 
2570                 /* try to get the attachment's size; this may fail for weird
2571                  * file systems, like obex, upnp... */
2572                 if (allowed_size != 0 &&
2573                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2574                         size = info->size;
2575                         if (size > allowed_size) {
2576                                 modest_platform_information_banner (NULL, NULL, 
2577                                                                     _FM("sfil_ib_opening_not_allowed"));
2578                                 g_free (filename);
2579                                 return 0;
2580                         }
2581                 } else
2582                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2583                 
2584                 stream = create_stream_for_uri (uri);
2585                 
2586                 if (stream == NULL) {
2587
2588                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2589
2590                         g_object_unref (mime_part);
2591                         g_free (filename);
2592                         gnome_vfs_file_info_unref (info);
2593                         return 0;
2594                 }
2595
2596                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2597                 g_object_unref (stream);
2598                 
2599                 content_id = g_strdup_printf ("%d", priv->next_cid);
2600                 tny_mime_part_set_content_id (mime_part, content_id);
2601                 g_free (content_id);
2602                 priv->next_cid++;
2603                 
2604                 basename = g_path_get_basename (filename);
2605                 tny_mime_part_set_filename (mime_part, basename);
2606                 g_free (basename);
2607                 
2608                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2609                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2610                                                         mime_part,
2611                                                         info->size == 0, info->size);
2612                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2613                 gtk_widget_show_all (priv->attachments_caption);
2614                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2615                 g_free (filename);
2616                 g_object_unref (mime_part);
2617                 gnome_vfs_file_info_unref (info);
2618         }
2619
2620         return size;
2621 }
2622
2623 void
2624 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2625                                            TnyList *att_list)
2626 {
2627         ModestMsgEditWindowPrivate *priv;
2628         TnyIterator *iter;
2629
2630         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2631         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2632
2633         if (att_list == NULL) {
2634                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2635                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2636                         g_object_unref (att_list);
2637                         return;
2638                 }
2639                 
2640         } else {
2641                 g_object_ref (att_list);
2642         }
2643
2644         if (tny_list_get_length (att_list) == 0) {
2645                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2646         } else {
2647                 gboolean dialog_response;
2648                 gchar *message = NULL;
2649                 gchar *filename = NULL;
2650
2651                 if (tny_list_get_length (att_list) == 1) {
2652                         TnyMimePart *part;
2653                         iter = tny_list_create_iterator (att_list);
2654                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2655                         g_object_unref (iter);
2656                         if (TNY_IS_MSG (part)) {
2657                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2658                                 if (header) {
2659                                         filename = tny_header_dup_subject (header);
2660                                         g_object_unref (header);
2661                                 }
2662                                 if (filename == NULL) {
2663                                         filename = g_strdup (_("mail_va_no_subject"));
2664                                 }
2665                         } else {
2666                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2667                         }
2668                         g_object_unref (part);
2669                 } else {
2670                         filename = g_strdup ("");
2671                 }
2672                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2673                                                     "emev_nc_delete_attachments",
2674                                                     tny_list_get_length (att_list)), filename);
2675                 g_free (filename);
2676
2677                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2678                                                                            message);
2679                 g_free (message);
2680
2681                 if (dialog_response != GTK_RESPONSE_OK) {
2682                         g_object_unref (att_list);
2683                         return;
2684                 }
2685
2686                 for (iter = tny_list_create_iterator (att_list);
2687                      !tny_iterator_is_done (iter);
2688                      tny_iterator_next (iter)) {
2689                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2690                         const gchar *att_id;
2691                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2692
2693                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2694                                                                    mime_part);
2695                         if (tny_list_get_length (priv->attachments) == 0)
2696                                 gtk_widget_hide (priv->attachments_caption);
2697                         att_id = tny_mime_part_get_content_id (mime_part);
2698                         if (att_id != NULL)
2699                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2700                                                                  att_id);
2701                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2702                         g_object_unref (mime_part);
2703                 }
2704                 g_object_unref (iter);
2705         }
2706
2707         g_object_unref (att_list);
2708
2709         /* if the last attachment has been removed, focus the Subject: field */
2710         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2711                 gtk_widget_grab_focus (priv->subject_field);
2712 }
2713
2714 static void
2715 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2716                                             gpointer userdata)
2717 {
2718         ModestMsgEditWindowPrivate *priv;
2719         GdkColor *new_color;
2720         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2721         
2722 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2723         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2724 #else 
2725         GdkColor col;
2726         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2727         new_color = &col;
2728 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2729
2730         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2731         
2732         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2733
2734 }
2735
2736 static void
2737 font_size_clicked (GtkToolButton *button,
2738                    ModestMsgEditWindow *window)
2739 {
2740         ModestMsgEditWindowPrivate *priv;
2741         GtkWidget *selector, *dialog;
2742         
2743         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2744
2745         selector = hildon_touch_selector_new ();
2746         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2747         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2748
2749         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2750         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2751         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2752
2753         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2754                 gint new_index;
2755                 gchar *size_text;
2756                 gchar *markup;
2757                 WPTextBufferFormat format;
2758
2759                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2760
2761                 memset (&format, 0, sizeof (format));
2762                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2763
2764                 format.cs.font_size = TRUE;
2765                 format.cs.text_position = TRUE;
2766                 format.cs.font = TRUE;
2767                 format.font_size = new_index;
2768 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2769
2770                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2771                                                    GINT_TO_POINTER (new_index)))
2772                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2773                 
2774                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2775                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2776                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2777                                       size_text, "</span>", NULL);
2778                 g_free (size_text);
2779                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2780                 g_free (markup);
2781
2782         }
2783         gtk_widget_destroy (dialog);
2784
2785         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2786
2787 }
2788
2789 static void
2790 font_face_clicked (GtkToolButton *button,
2791                    ModestMsgEditWindow *window)
2792 {
2793         ModestMsgEditWindowPrivate *priv;
2794         GtkWidget *selector, *dialog;
2795         GtkCellRenderer *renderer;
2796         
2797         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2798
2799         selector = hildon_touch_selector_new ();
2800         renderer = gtk_cell_renderer_text_new ();
2801         g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2802         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2803                                              renderer, "family", 0, "text", 0, NULL);
2804         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2805
2806         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2807         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2808         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2809
2810         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2811                 gint new_font_index;
2812                 GtkTreePath *path;
2813                 GtkTreeIter iter;
2814
2815                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2816                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2817                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2818                         gchar *face_name;
2819                         gchar *markup;
2820
2821                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2822
2823                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2824                                                            GINT_TO_POINTER(new_font_index)))
2825                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2826
2827                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2828                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2829
2830                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2831                         g_free (face_name);
2832                         g_free (markup);
2833                 }
2834                 gtk_tree_path_free (path);
2835
2836         }
2837         gtk_widget_destroy (dialog);
2838
2839         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2840
2841 }
2842
2843 void
2844 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2845                                 gboolean show)
2846 {
2847         ModestMsgEditWindowPrivate *priv = NULL;
2848         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2849
2850         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2851         if (!priv->update_caption_visibility)
2852                 return;
2853
2854         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2855         if (show)
2856                 gtk_widget_show (priv->cc_caption);
2857         else
2858                 gtk_widget_hide (priv->cc_caption);
2859
2860         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2861 }
2862
2863 void
2864 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2865                                  gboolean show)
2866 {
2867         ModestMsgEditWindowPrivate *priv = NULL;
2868         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2869
2870         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2871         if (!priv->update_caption_visibility)
2872                 return;
2873
2874         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2875         if (show)
2876                 gtk_widget_show (priv->bcc_caption);
2877         else
2878                 gtk_widget_hide (priv->bcc_caption);
2879
2880         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2881 }
2882
2883 static void
2884 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2885                                          ModestRecptEditor *editor)
2886 {
2887         ModestMsgEditWindowPrivate *priv;
2888
2889         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2890         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2891         
2892         /* we check for low-mem; in that case, show a warning, and don't allow
2893          * for the addressbook
2894          */
2895         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2896                 return;
2897
2898         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2899
2900         if (editor == NULL) {
2901                 GtkWidget *view_focus;
2902                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2903
2904                 /* This code should be kept in sync with ModestRecptEditor. The
2905                    textview inside the recpt editor is the one that really gets the
2906                    focus. As it's inside a scrolled window, and this one inside the
2907                    hbox recpt editor inherits from, we'll need to go up in the 
2908                    hierarchy to know if the text view is part of the recpt editor
2909                    or if it's a different text entry */
2910
2911                 if (gtk_widget_get_parent (view_focus)) {
2912                         GtkWidget *first_parent;
2913
2914                         first_parent = gtk_widget_get_parent (view_focus);
2915                         if (gtk_widget_get_parent (first_parent) && 
2916                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2917                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2918                         }
2919                 }
2920
2921                 if (editor == NULL)
2922                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2923
2924         }
2925
2926         modest_address_book_select_addresses (editor);
2927
2928 }
2929
2930 void
2931 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2932 {
2933         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2934
2935         modest_msg_edit_window_open_addressbook (window, NULL);
2936 }
2937
2938 static void
2939 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2940                                      gboolean show_toolbar)
2941 {
2942         ModestWindowPrivate *parent_priv;
2943         ModestMsgEditWindowPrivate *priv;
2944
2945         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2946         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2947         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2948
2949         /* We can not just use the code of
2950            modest_msg_edit_window_setup_toolbar because it has a
2951            mixture of both initialization and creation code. */
2952         if (show_toolbar) {
2953                 gint current_format;
2954                 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2955                         ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2956                 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2957                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2958                 } else {
2959                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2960                 }
2961         } else {
2962                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2963         }
2964 }
2965
2966 void
2967 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2968                                            TnyHeaderFlags priority_flags)
2969 {
2970         ModestMsgEditWindowPrivate *priv;
2971         ModestWindowPrivate *parent_priv;
2972
2973         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2974
2975         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2976         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2977
2978         if (priv->priority_flags != priority_flags) {
2979                 GtkAction *priority_action = NULL;
2980
2981                 priv->priority_flags = priority_flags;
2982
2983                 switch (priority_flags) {
2984                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2985                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2986                                                       MODEST_HEADER_ICON_HIGH, 
2987                                                       HILDON_ICON_SIZE_SMALL);
2988                         gtk_widget_show (priv->priority_icon);
2989                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2990                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2991                         break;
2992                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2993                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2994                                                       MODEST_HEADER_ICON_LOW,
2995                                                       HILDON_ICON_SIZE_SMALL);
2996                         gtk_widget_show (priv->priority_icon);
2997                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2998                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2999                         break;
3000                 default:
3001                         gtk_widget_hide (priv->priority_icon);
3002                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3003                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3004                         break;
3005                 }
3006                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3007                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3008         }
3009         gtk_widget_queue_resize (priv->subject_box);
3010 }
3011
3012 void
3013 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3014                                         gint file_format)
3015 {
3016         ModestMsgEditWindowPrivate *priv;
3017         ModestWindowPrivate *parent_priv;
3018         gint current_format;
3019
3020         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3021
3022         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3023         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3024
3025         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3026                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3027
3028         gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3029
3030         if (parent_priv->toolbar) {
3031                 if (file_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3032                         gtk_widget_hide (parent_priv->toolbar);
3033                 } else {
3034                         gtk_widget_show (parent_priv->toolbar);
3035                 }
3036         }
3037
3038         if (current_format != file_format) {
3039                 switch (file_format) {
3040                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3041                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3042                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3043                         break;
3044                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3045                 {
3046                         GtkWidget *dialog;
3047                         gint response;
3048                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3049                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3050                         gtk_widget_destroy (dialog);
3051                         if (response == GTK_RESPONSE_OK) {
3052                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3053                                 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
3054                         } else {
3055                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3056                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3057                         }
3058                 }
3059                         break;
3060                 }
3061                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3062                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3063                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3064         }
3065 }
3066
3067 void
3068 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3069 {
3070         GtkWidget *dialog;
3071         ModestMsgEditWindowPrivate *priv;
3072         WPTextBufferFormat oldfmt, fmt;
3073         gint old_position = 0;
3074         gint response = 0;
3075         gint position = 0;
3076         gint font_size;
3077         GdkColor *color = NULL;
3078         gboolean bold, bold_set, italic, italic_set;
3079         gboolean underline, underline_set;
3080         gboolean strikethrough, strikethrough_set;
3081         gboolean position_set;
3082         gboolean font_size_set, font_set, color_set;
3083         gchar *font_name;
3084
3085         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3086         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3087         
3088         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3089         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3090                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
3091
3092         /* First we get the currently selected font information */
3093         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3094
3095         switch (oldfmt.text_position) {
3096         case TEXT_POSITION_NORMAL:
3097                 old_position = 0;
3098                 break;
3099         case TEXT_POSITION_SUPERSCRIPT:
3100                 old_position = 1;
3101                 break;
3102         default:
3103                 old_position = -1;
3104                 break;
3105         }
3106
3107         g_object_set (G_OBJECT (dialog),
3108                       "bold", oldfmt.bold != FALSE,
3109                       "bold-set", !oldfmt.cs.bold,
3110                       "underline", oldfmt.underline != FALSE,
3111                       "underline-set", !oldfmt.cs.underline,
3112                       "italic", oldfmt.italic != FALSE,
3113                       "italic-set", !oldfmt.cs.italic,
3114                       "strikethrough", oldfmt.strikethrough != FALSE,
3115                       "strikethrough-set", !oldfmt.cs.strikethrough,
3116                       "color", &oldfmt.color,
3117                       "color-set", !oldfmt.cs.color,
3118                       "size", wp_font_size[oldfmt.font_size],
3119                       "size-set", !oldfmt.cs.font_size,
3120                       "position", old_position,
3121                       "position-set", !oldfmt.cs.text_position,
3122                       "family", wp_get_font_name (oldfmt.font),
3123                       "family-set", !oldfmt.cs.font,
3124                       NULL);
3125
3126         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
3127                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
3128         gtk_widget_show_all (dialog);
3129         priv->font_dialog = dialog;
3130         response = gtk_dialog_run (GTK_DIALOG (dialog));
3131         priv->font_dialog = NULL;
3132         if (response == GTK_RESPONSE_OK) {
3133
3134                 g_object_get( dialog,
3135                               "bold", &bold,
3136                               "bold-set", &bold_set,
3137                               "underline", &underline,
3138                               "underline-set", &underline_set,
3139                               "italic", &italic,
3140                               "italic-set", &italic_set,
3141                               "strikethrough", &strikethrough,
3142                               "strikethrough-set", &strikethrough_set,
3143                               "color", &color,
3144                               "color-set", &color_set,
3145                               "size", &font_size,
3146                               "size-set", &font_size_set,
3147                               "family", &font_name,
3148                               "family-set", &font_set,
3149                               "position", &position,
3150                               "position-set", &position_set,
3151                               NULL );
3152                 
3153         }       
3154
3155         if (response == GTK_RESPONSE_OK) {
3156                 memset(&fmt, 0, sizeof(fmt));
3157                 if (bold_set) {
3158                         fmt.bold = bold;
3159                         fmt.cs.bold = TRUE;
3160                 }
3161                 if (italic_set) {
3162                         fmt.italic = italic;
3163                         fmt.cs.italic = TRUE;
3164                 }
3165                 if (underline_set) {
3166                         fmt.underline = underline;
3167                         fmt.cs.underline = TRUE;
3168                 }
3169                 if (strikethrough_set) {
3170                         fmt.strikethrough = strikethrough;
3171                         fmt.cs.strikethrough = TRUE;
3172                 }
3173                 if (position_set) {
3174                         fmt.text_position =
3175                                 ( position == 0 )
3176                                 ? TEXT_POSITION_NORMAL
3177                                 : ( ( position == 1 )
3178                                     ? TEXT_POSITION_SUPERSCRIPT
3179                                     : TEXT_POSITION_SUBSCRIPT );
3180                         fmt.cs.text_position = TRUE;
3181                         fmt.font_size = oldfmt.font_size;
3182                 }
3183                 if (color_set) {
3184                         fmt.color = *color;
3185                         fmt.cs.color = TRUE;
3186                 }
3187                 if (font_set) {
3188                         fmt.font = wp_get_font_index(font_name,
3189                                                      DEFAULT_FONT);
3190                         fmt.cs.font = TRUE;
3191                 }
3192                 g_free(font_name);
3193                 if (font_size_set) {
3194                         fmt.cs.font_size = TRUE;
3195                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3196                 }
3197                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3198                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3199         }
3200         gtk_widget_destroy (dialog);
3201         
3202         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3203 }
3204
3205 void
3206 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3207 {
3208         ModestMsgEditWindowPrivate *priv;
3209
3210         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3211         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3212         
3213         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3214
3215         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3216         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3217 }
3218
3219 void
3220 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3221 {
3222         ModestMsgEditWindowPrivate *priv;
3223
3224         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3225         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226         
3227         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3228
3229         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3230         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3231
3232 }
3233
3234 static void  
3235 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3236 {
3237         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3238
3239         priv->can_undo = can_undo;
3240 }
3241
3242 static void  
3243 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3244 {
3245         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3246
3247         priv->can_redo = can_redo;
3248 }
3249
3250 gboolean            
3251 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3252 {
3253         ModestMsgEditWindowPrivate *priv;
3254         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3255         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3256
3257         return priv->can_undo;
3258 }
3259
3260 gboolean            
3261 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3262 {
3263         ModestMsgEditWindowPrivate *priv;
3264         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3265         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3266
3267         return priv->can_redo;
3268 }
3269
3270
3271 static void
3272 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3273 {
3274         GtkTextIter iter;
3275         GtkTextIter match_start, match_end;
3276
3277         if (image_id == NULL)
3278                 return;
3279
3280         gtk_text_buffer_get_start_iter (buffer, &iter);
3281
3282         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3283                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3284                 GSList *node;
3285                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3286                         GtkTextTag *tag = (GtkTextTag *) node->data;
3287                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3288                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3289                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3290                                         gint offset;
3291                                         offset = gtk_text_iter_get_offset (&match_start);
3292                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3293                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3294                                 }
3295                         }
3296                 }
3297                 gtk_text_iter_forward_char (&iter);
3298         }
3299 }
3300
3301 gboolean
3302 message_is_empty (ModestMsgEditWindow *window)
3303 {
3304         ModestMsgEditWindowPrivate *priv = NULL;
3305
3306         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3307         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3308
3309         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3310          * so we can ignore markup.
3311          */
3312         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3313         gint count = 0;
3314         if (buf)
3315                 count = gtk_text_buffer_get_char_count (buf);
3316
3317         return count == 0;
3318 }
3319
3320 static gboolean
3321 msg_body_focus (GtkWidget *focus,
3322                 GdkEventFocus *event,
3323                 gpointer userdata)
3324 {
3325         
3326         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3327         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3328         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3329         return FALSE;
3330 }
3331
3332 static void
3333 recpt_field_changed (GtkTextBuffer *buffer,
3334                   ModestMsgEditWindow *editor)
3335 {
3336         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3337         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3338 }
3339
3340 static void
3341 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3342 {
3343         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3344         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3345 }
3346
3347 void
3348 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3349                                      gboolean modified)
3350 {
3351         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3352         GtkTextBuffer *buffer;
3353
3354         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3355         gtk_text_buffer_set_modified (buffer, modified);
3356         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3357         gtk_text_buffer_set_modified (buffer, modified);
3358         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3359         gtk_text_buffer_set_modified (buffer, modified);
3360         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3361 }
3362
3363 gboolean
3364 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3365 {
3366         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3367         const char *account_name;
3368         GtkTextBuffer *buffer;
3369
3370         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3371         if (gtk_text_buffer_get_modified (buffer))
3372                 return TRUE;
3373         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3374         if (gtk_text_buffer_get_modified (buffer))
3375                 return TRUE;
3376         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3377         if (gtk_text_buffer_get_modified (buffer))
3378                 return TRUE;
3379         if (gtk_text_buffer_get_modified (priv->text_buffer))
3380                 return TRUE;
3381
3382         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3383         if (priv->original_mailbox) {
3384                 if (!account_name || strcmp (account_name, priv->original_mailbox))
3385                         return TRUE;
3386         } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3387                 return TRUE;
3388         }
3389
3390         return FALSE;
3391 }
3392
3393
3394
3395
3396 gboolean
3397 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3398 {
3399         ModestMsgEditWindowPrivate *priv = NULL;
3400         
3401         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3402         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3403
3404         /* check if there's no recipient added */
3405         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3406             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3407             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3408                 /* no recipient contents, then select contacts */
3409                 modest_msg_edit_window_open_addressbook (window, NULL);
3410                 return FALSE;
3411         }
3412
3413         g_object_ref (window);
3414         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3415                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3416                 g_object_unref (window);
3417                 return FALSE;
3418         }
3419         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3420                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3421                 g_object_unref (window);
3422                 return FALSE;
3423         }
3424         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3425                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3426                 g_object_unref (window);
3427                 return FALSE;
3428         }
3429
3430         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3431             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3432                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3433         g_object_unref (window);
3434
3435         return TRUE;
3436
3437 }
3438
3439 static void
3440 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3441                                                ModestMsgEditWindow *window)
3442 {
3443         modest_msg_edit_window_offer_attach_file (window);
3444 }
3445
3446 const gchar *
3447 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3448 {
3449         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3450
3451         return priv->clipboard_text;
3452 }
3453
3454 static void
3455 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3456                                                GdkEvent *event,
3457                                                ModestMsgEditWindow *window)
3458 {
3459         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3460         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3461         gchar *text = NULL;
3462
3463         /* It could happen that the window was already closed */
3464         if (!GTK_WIDGET_VISIBLE (window))
3465                 return;
3466
3467         g_object_ref (window);
3468         text = gtk_clipboard_wait_for_text (selection_clipboard);
3469
3470         if (priv->clipboard_text != NULL) {
3471                 g_free (priv->clipboard_text);
3472         }
3473         priv->clipboard_text = text;
3474
3475         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3476
3477         g_object_unref (window);
3478 }
3479
3480 static gboolean clipboard_owner_change_idle (gpointer userdata)
3481 {
3482         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3483         ModestMsgEditWindowPrivate *priv;
3484
3485         gdk_threads_enter ();
3486         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3487         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3488
3489         priv->clipboard_owner_idle = 0;
3490         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3491         gdk_threads_leave ();
3492
3493         return FALSE;
3494 }
3495
3496 static void
3497 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3498 {
3499         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3500         if (priv->clipboard_owner_idle == 0) {
3501                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3502                                                               clipboard_owner_change_idle, 
3503                                                               g_object_ref (window),
3504                                                               g_object_unref);
3505         }
3506 }
3507
3508 static void 
3509 subject_field_move_cursor (GtkEntry *entry,
3510                            GtkMovementStep step,
3511                            gint a1,
3512                            gboolean a2,
3513                            gpointer window)
3514 {
3515         /* It could happen that the window was already closed */
3516         if (!GTK_WIDGET_VISIBLE (window))
3517                 return;
3518
3519         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3520 }
3521
3522 static void 
3523 update_window_title (ModestMsgEditWindow *window)
3524 {
3525         ModestMsgEditWindowPrivate *priv = NULL;
3526         const gchar *subject;
3527
3528         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3529         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3530         if (subject == NULL || subject[0] == '\0')
3531                 subject = _("mail_va_new_email");
3532
3533         gtk_window_set_title (GTK_WINDOW (window), subject);
3534
3535 }
3536
3537
3538 static void  
3539 body_insert_text (GtkTextBuffer *buffer, 
3540                   GtkTextIter *location,
3541                   gchar *text,
3542                   gint len,
3543                   ModestMsgEditWindow *window)
3544 {
3545         GtkTextIter end_iter;
3546         gint offset;
3547
3548         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3549
3550         offset = gtk_text_iter_get_offset (&end_iter);
3551
3552         if (offset + len > MAX_BODY_LENGTH) {
3553                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3554                 if (offset < MAX_BODY_LENGTH)
3555                 {
3556                         gchar *result;
3557
3558                         /* Prevent endless recursion */
3559                         result = g_strndup (text, MAX_BODY_LENGTH - offset);
3560                         g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3561                         g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3562                                                (gpointer) result, (gpointer) MAX_BODY_LENGTH - offset,
3563                                                (gpointer) window);
3564                         g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3565                 }
3566
3567         }
3568         if (offset + len > MAX_BODY_LENGTH) {
3569                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3570                                                 _CS("ckdg_ib_maximum_characters_reached"));
3571         }
3572 }
3573
3574 static void  
3575 subject_field_changed (GtkEditable *editable, 
3576                        ModestMsgEditWindow *window)
3577 {
3578         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3579         update_window_title (window);
3580         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3581         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3582         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3583 }
3584 static void  
3585 subject_field_insert_text (GtkEditable *editable, 
3586                            gchar *new_text,
3587                            gint new_text_length,
3588                            gint *position,
3589                            ModestMsgEditWindow *window)
3590 {
3591         GString *result = g_string_new ("");
3592         gchar *current;
3593         gint result_len = 0;
3594         const gchar *entry_text = NULL;
3595         gint old_length;
3596
3597         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3598         old_length = g_utf8_strlen (entry_text, -1);
3599
3600         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3601                 gunichar c = g_utf8_get_char_validated (current, 8);
3602                 /* Invalid unichar, stop */
3603                 if (c == -1)
3604                         break;
3605                 /* a bullet */
3606                 if (c == 0x2022)
3607                         continue;
3608                 result = g_string_append_unichar (result, c);
3609                 result_len++;
3610         }
3611
3612         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3613                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3614                 if (result_len > 0)
3615                 {
3616                         /* Prevent endless recursion */
3617                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3618                         g_signal_emit_by_name (editable, "insert-text", 
3619                                                (gpointer) result->str, (gpointer) result->len,
3620                                                (gpointer) position, (gpointer) window);
3621                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3622                 }
3623         }
3624
3625         if (result_len + old_length > 1000) {
3626                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3627                                                 _CS("ckdg_ib_maximum_characters_reached"));
3628         }
3629         g_string_free (result, TRUE);
3630 }
3631
3632 void
3633 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3634                                             gboolean show)
3635 {
3636         ModestMsgEditWindowPrivate *priv = NULL;
3637
3638         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3639         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3640
3641         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3642
3643         if (show) {
3644                 gtk_widget_show_all (priv->find_toolbar);
3645                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3646         } else {
3647                 gtk_widget_hide_all (priv->find_toolbar);
3648                 gtk_widget_grab_focus (priv->msg_body);
3649         }
3650 }
3651
3652 static gboolean 
3653 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3654                                           const gchar *str,
3655                                           GtkTextIter *match_start,
3656                                           GtkTextIter *match_end)
3657 {
3658         GtkTextIter end_iter;
3659         gchar *str_casefold;
3660         gint str_chars_n;
3661         gchar *range_text;
3662         gchar *range_casefold;
3663         gint offset;
3664         gint range_chars_n;
3665         gboolean result = FALSE;
3666
3667         if (str == NULL)
3668                 return TRUE;
3669         
3670         /* get end iter */
3671         end_iter = *iter;
3672         gtk_text_iter_forward_to_end (&end_iter);
3673
3674         str_casefold = g_utf8_casefold (str, -1);
3675         str_chars_n = strlen (str);
3676
3677         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3678         range_casefold = g_utf8_casefold (range_text, -1);
3679         range_chars_n = strlen (range_casefold);
3680
3681         if (range_chars_n < str_chars_n) {
3682                 g_free (str_casefold);
3683                 g_free (range_text);
3684                 g_free (range_casefold);
3685                 return FALSE;
3686         }
3687
3688         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3689                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3690                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3691                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3692                         result = TRUE;
3693                         if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3694                                                            match_start, match_end, NULL)) {
3695                                 g_warning ("Matched string with collate, but not matched in model");
3696                         }
3697                         g_free (found_text);
3698                 }
3699                 g_free (range_subtext);
3700                 if (result)
3701                         break;
3702         }
3703         g_free (str_casefold);
3704         g_free (range_text);
3705         g_free (range_casefold);
3706
3707         return result;
3708 }
3709
3710
3711 static void 
3712 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3713                                             ModestMsgEditWindow *window)
3714 {
3715         gchar *current_search = NULL;
3716         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3717         gboolean result;
3718         GtkTextIter selection_start, selection_end;
3719         GtkTextIter match_start, match_end;
3720         gboolean continue_search = FALSE;
3721
3722         if (message_is_empty (window)) {
3723                 g_free (priv->last_search);
3724                 priv->last_search = NULL;
3725                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3726                 return;
3727         }
3728
3729         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3730         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3731                 g_free (current_search);
3732                 g_free (priv->last_search);
3733                 priv->last_search = NULL;
3734                 /* Information banner about empty search */
3735                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3736                 return;
3737         }
3738
3739         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3740                 continue_search = TRUE;
3741         } else {
3742                 g_free (priv->last_search);
3743                 priv->last_search = g_strdup (current_search);
3744         }
3745
3746         if (continue_search) {
3747                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3748                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3749                                                                    &match_start, &match_end);
3750                 if (!result)
3751                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3752         } else {
3753                 GtkTextIter buffer_start;
3754                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3755                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3756                                                                    &match_start, &match_end);
3757                 if (!result)
3758                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3759         }
3760
3761         /* Mark as selected the string found in search */
3762         if (result) {
3763                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3764                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3765                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3766         } else {
3767                 g_free (priv->last_search);
3768                 priv->last_search = NULL;
3769         }
3770         g_free (current_search);
3771 }
3772
3773 gboolean 
3774 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3775 {
3776         ModestMsgEditWindowPrivate *priv;
3777
3778         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3779         return priv->sent;
3780 }
3781
3782 void 
3783 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3784                                  gboolean sent)
3785 {
3786         ModestMsgEditWindowPrivate *priv;
3787
3788         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3789         priv->sent = sent;
3790 }
3791
3792 static void
3793 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3794                                           ModestMsgEditWindow *window)
3795 {
3796         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3797 }
3798
3799 void
3800 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3801                                   TnyMsg *draft)
3802 {
3803         ModestMsgEditWindowPrivate *priv;
3804         TnyHeader *header = NULL;
3805
3806         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3807         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3808
3809         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3810
3811         if (priv->draft_msg != NULL) {
3812                 g_object_unref (priv->draft_msg);
3813         }
3814
3815         if (draft != NULL) {
3816                 g_object_ref (draft);
3817                 header = tny_msg_get_header (draft);
3818                 if (priv->msg_uid) {
3819                         g_free (priv->msg_uid);
3820                         priv->msg_uid = NULL;
3821                 }
3822                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3823         }
3824
3825         priv->draft_msg = draft;
3826 }
3827
3828 static void  
3829 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3830                        GtkTextIter *start, GtkTextIter *end,
3831                        gpointer userdata)
3832 {
3833         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3834         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3835         gchar *tag_name;
3836
3837         if (tag == NULL) return;
3838         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3839         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3840                 replace_with_images (window, priv->images);
3841         }
3842 }
3843
3844 void                    
3845 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3846                                  TnyMimePart *part)
3847 {
3848         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3849
3850         g_return_if_fail (TNY_IS_MIME_PART (part));
3851         tny_list_prepend (priv->attachments, (GObject *) part);
3852         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3853         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3854         gtk_widget_show_all (priv->attachments_caption);
3855         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3856 }
3857
3858 const gchar*    
3859 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3860 {
3861         ModestMsgEditWindowPrivate *priv;
3862
3863         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3864         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3865
3866         return priv->msg_uid;
3867 }
3868
3869 GtkWidget *
3870 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3871                                          ModestMsgEditWindowWidgetType widget_type)
3872 {
3873         ModestMsgEditWindowPrivate *priv;
3874
3875         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3876         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3877
3878         switch (widget_type) {
3879         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3880                 return priv->msg_body;
3881                 break;
3882         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3883                 return priv->to_field;
3884                 break;
3885         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3886                 return priv->cc_field;
3887                 break;
3888         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3889                 return priv->bcc_field;
3890                 break;
3891         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3892                 return priv->subject_field;
3893                 break;
3894         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3895                 return priv->attachments_view;
3896                 break;
3897         default:
3898                 return NULL;
3899         }
3900 }
3901
3902 static void 
3903 remove_tags (WPTextBuffer *buffer)
3904 {
3905         GtkTextIter start, end;
3906
3907         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3908         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3909
3910         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3911 }
3912
3913 static void
3914 on_account_removed (TnyAccountStore *account_store, 
3915                     TnyAccount *account,
3916                     gpointer user_data)
3917 {
3918         /* Do nothing if it's a store account, because we use the
3919            transport to send the messages */
3920         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3921                 const gchar *parent_acc = NULL;
3922                 const gchar *our_acc = NULL;
3923
3924                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3925                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3926                 /* Close this window if I'm showing a message of the removed account */
3927                 if (strcmp (parent_acc, our_acc) == 0)
3928                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3929         }
3930 }
3931
3932 static void update_signature (ModestMsgEditWindow *self,
3933                               const gchar *old_account, 
3934                               const gchar *new_account)
3935 {
3936         ModestMsgEditWindowPrivate *priv;
3937         gboolean has_old_signature, has_new_signature;
3938         GtkTextIter iter;
3939         GtkTextIter match_start, match_end;
3940         ModestAccountMgr *mgr;
3941         gchar *signature;
3942         gchar *full_signature;
3943
3944         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3945
3946         gtk_text_buffer_begin_user_action (priv->text_buffer);
3947
3948         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3949         mgr = modest_runtime_get_account_mgr ();
3950
3951
3952         if (old_account) {
3953                 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
3954                 if (has_old_signature) {
3955                         full_signature = g_strconcat ("\n--\n", signature, NULL);
3956                         if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3957                                 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3958                                 iter = match_start;
3959                         } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3960                                                                  &match_start, &match_end, NULL)) {
3961                                 iter = match_start;
3962                         }
3963                         g_free (full_signature);
3964                 }
3965                 g_free (signature);
3966         }
3967
3968         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3969         signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
3970         if (has_new_signature) {
3971                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3972                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3973                 g_free (full_signature);
3974         }
3975         g_free (signature);
3976         gtk_text_buffer_end_user_action (priv->text_buffer);
3977 }
3978
3979 static void
3980 from_field_changed (HildonPickerButton *button,
3981                     ModestMsgEditWindow *self)
3982 {
3983         ModestMsgEditWindowPrivate *priv;
3984         gchar *old_account, *new_account;
3985
3986         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3987
3988         old_account = priv->last_from_account;
3989         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3990         new_account = priv->last_from_account;
3991
3992         update_signature (self, old_account, new_account);
3993
3994 }
3995
3996 typedef struct _MessageSettingsHelper {
3997         ModestMsgEditWindow *window;
3998         GSList *priority_group;
3999         GSList *format_group;
4000         GtkToggleButton *current_priority;
4001         GtkToggleButton *current_format;
4002 } MessageSettingsHelper;
4003
4004 static void
4005 on_priority_toggle (GtkToggleButton *button, 
4006                     MessageSettingsHelper *helper)
4007 {
4008         GSList *node;
4009         ModestMsgEditWindowPrivate *priv;
4010
4011         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4012         if (gtk_toggle_button_get_active (button)) {
4013
4014                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4015                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4016                         if ((node_button != button) &&
4017                             gtk_toggle_button_get_active (node_button)) {
4018                                 gtk_toggle_button_set_active (node_button, FALSE);
4019                         }
4020                 }
4021                 helper->current_priority = button;
4022         } else {
4023                 gboolean found = FALSE;
4024                 /* If no one is active, activate it again */
4025                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4026                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4027                         if (gtk_toggle_button_get_active (node_button)) {
4028                                 found = TRUE;
4029                                 break;
4030                         }
4031                 }
4032                 if (!found) {
4033                         gtk_toggle_button_set_active (button, TRUE);
4034                 }
4035         }
4036 }
4037
4038 static void
4039 on_format_toggle (GtkToggleButton *button,
4040                   MessageSettingsHelper *helper)
4041 {
4042         GSList *node;
4043         ModestMsgEditWindowPrivate *priv;
4044
4045         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4046         if (gtk_toggle_button_get_active (button)) {
4047
4048                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4049                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4050                         if ((node_button != button) &&
4051                             gtk_toggle_button_get_active (node_button)) {
4052                                 gtk_toggle_button_set_active (node_button, FALSE);
4053                         }
4054                 }
4055                 helper->current_format = button;
4056         } else {
4057                 gboolean found = FALSE;
4058                 /* If no one is active, activate it again */
4059                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4060                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4061                         if (gtk_toggle_button_get_active (node_button)) {
4062                                 found = TRUE;
4063                                 break;
4064                         }
4065                 }
4066                 if (!found) {
4067                         gtk_toggle_button_set_active (button, TRUE);
4068                 }
4069         }
4070
4071 }
4072
4073 static void
4074 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4075 {
4076         GtkWidget *dialog;
4077         GtkWidget *align;
4078         GtkWidget *vbox;
4079         GtkWidget *priority_hbox;
4080         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4081         GtkWidget *captioned;
4082         GtkSizeGroup *title_sizegroup, *value_sizegroup;
4083         GtkWidget *format_hbox;
4084         GtkWidget *html_toggle, *text_toggle;
4085         ModestMsgEditWindowPrivate *priv;
4086         MessageSettingsHelper helper = {0,};
4087
4088         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4089         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4090         helper.window = window;
4091         helper.priority_group = NULL;
4092         helper.format_group = NULL;
4093
4094         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4095         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4096
4097         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4098                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4099                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4100         vbox = gtk_vbox_new (FALSE, 0);
4101         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4102         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4103         gtk_container_add (GTK_CONTAINER (align), vbox);
4104         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4105         gtk_widget_show (align);
4106         gtk_widget_show (vbox);
4107
4108         /* Priority toggles */
4109         priority_hbox = gtk_hbox_new (TRUE, 0);
4110         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4111         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4112         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4113         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4114         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4115         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4116         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4117         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4118         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4119         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4120         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4121         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4122         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4123         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4124         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4125         gtk_widget_show_all (priority_hbox);
4126         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4127                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4128         gtk_widget_show (captioned);
4129         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4130
4131         /* format toggles */
4132         format_hbox = gtk_hbox_new (TRUE, 0);
4133         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4134         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4135         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4136         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4137         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4138         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4139         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4140         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4141         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4142         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4143         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4144         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4145         gtk_widget_show_all (format_hbox);
4146         gtk_widget_show (format_hbox);
4147         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4148
4149
4150         g_object_unref (title_sizegroup);
4151         g_object_unref (value_sizegroup);
4152
4153         /* Set current values */
4154         switch (priv->priority_flags) {
4155         case TNY_HEADER_FLAG_HIGH_PRIORITY:
4156                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4157                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4158                 break;
4159         case TNY_HEADER_FLAG_LOW_PRIORITY:
4160                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4161                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4162                 break;
4163         default:
4164                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4165                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4166                 break;
4167         }
4168
4169         switch (modest_msg_edit_window_get_format (window)) {
4170         case MODEST_MSG_EDIT_FORMAT_TEXT:
4171                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4172                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4173                 break;
4174         case MODEST_MSG_EDIT_FORMAT_HTML:
4175         default:
4176                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4177                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4178                 break;
4179         }
4180
4181         /* Signal connects */
4182         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4183         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4184         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4185         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4186         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4187
4188         /* Save settings if the user clicked on done */
4189         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4190                 TnyHeaderFlags flags;
4191                 ModestMsgEditFormat old_format, new_format;
4192
4193                 /* Set priority flags */
4194                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4195                 if (priv->priority_flags !=  flags)
4196                         modest_msg_edit_window_set_priority_flags (window, flags);
4197
4198                 /* Set edit format */
4199                 old_format = modest_msg_edit_window_get_format (window);
4200                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4201                 if (old_format != new_format) {
4202                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4203                         modest_msg_edit_window_set_file_format (window, file_format);
4204                 }
4205         }
4206
4207         gtk_widget_destroy (dialog);
4208         g_slist_free (helper.priority_group);
4209 }
4210
4211 static void
4212 on_message_settings (GtkAction *action,
4213                      ModestMsgEditWindow *window)
4214 {
4215         modest_msg_edit_window_show_msg_settings_dialog (window);
4216 }
4217
4218 static void
4219 on_cc_button_toggled (HildonCheckButton *button,
4220                       ModestMsgEditWindow *window)
4221 {
4222         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4223
4224         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4225                                         hildon_check_button_get_active (button));
4226 }
4227
4228 static void
4229 on_bcc_button_toggled (HildonCheckButton *button,
4230                       ModestMsgEditWindow *window)
4231 {
4232         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4233
4234         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4235                                         hildon_check_button_get_active (button));
4236 }
4237
4238 static void 
4239 setup_menu (ModestMsgEditWindow *self)
4240 {
4241         ModestMsgEditWindowPrivate *priv = NULL;
4242
4243         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4244
4245         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4246
4247         /* Settings menu buttons */
4248         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4249                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4250                                            NULL);
4251         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4252                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4253                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4254
4255         priv->cc_button = hildon_check_button_new (0);
4256         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4257         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4258                                         FALSE);
4259         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4260                                                   NULL);
4261         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4262                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4263         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4264         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4265
4266         priv->bcc_button = hildon_check_button_new (0);
4267         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4268         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4269                                         FALSE);
4270         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4271                                                   NULL);
4272         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4273                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4274         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4275         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4276
4277         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4278                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4279                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4280         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("TODO: add attachment"), NULL,
4281                                            APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4282                                            NULL);
4283         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4284                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4285                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4286         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4287                                            APP_MENU_CALLBACK (on_message_settings),
4288                                            NULL);
4289         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4290                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4291                                            NULL);
4292 }
4293
4294 static void
4295 emit_open_addressbook (GtkButton *button,
4296                        ModestRecptEditor *editor)
4297 {
4298         g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4299 }
4300
4301 static GtkWidget *
4302 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4303                          const gchar *label, GtkWidget *control)
4304 {
4305         GtkWidget *abook_button;
4306         GtkWidget *align;
4307         GtkWidget *box;
4308         GtkWidget *label_widget;
4309
4310         box = gtk_hbox_new (FALSE, 0);
4311
4312         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4313         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4314
4315         abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4316         label_widget = gtk_label_new (label);
4317         gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4318         gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4319
4320         gtk_container_add (GTK_CONTAINER (align), abook_button);
4321         gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4322         gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4323         gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4324         if (title_size_group)
4325                 gtk_size_group_add_widget (title_size_group, label_widget);
4326         if (value_size_group)
4327                 gtk_size_group_add_widget (value_size_group, control);
4328
4329         g_signal_connect (G_OBJECT (abook_button), "clicked",
4330                           G_CALLBACK (emit_open_addressbook), control);
4331   
4332         return box;  
4333 }