Fixed several reference leaks
[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->send_button), "clicked",
742                           G_CALLBACK (modest_ui_actions_on_send), obj);
743
744         g_signal_connect (G_OBJECT (priv->from_field), "value-changed",
745                           G_CALLBACK (from_field_changed), obj);
746
747         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
748                           G_CALLBACK (msg_body_focus), obj);
749         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
750                           G_CALLBACK (msg_body_focus), obj);
751         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
752         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
753                           "changed", G_CALLBACK (recpt_field_changed), obj);
754         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
755                           "changed", G_CALLBACK (recpt_field_changed), obj);
756         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
757                           "changed", G_CALLBACK (recpt_field_changed), obj);
758         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
759         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
760         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
761
762         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
763         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
764  
765         priv->clipboard_change_handler_id = 
766                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
767                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
768         priv->default_clipboard_change_handler_id = 
769                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
770                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
771
772         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
773         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
774         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
775 }
776
777 static void
778 init_wp_text_view_style ()
779 {
780         static gboolean initialized = FALSE;
781
782         if (!initialized) {
783                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
784                 initialized = TRUE;
785         }
786 }       
787
788 static void
789 init_window (ModestMsgEditWindow *obj)
790 {
791         GtkWidget *to_caption, *subject_caption;
792         GtkWidget *main_vbox;
793         ModestMsgEditWindowPrivate *priv;
794         GtkActionGroup *action_group;
795         ModestWindowPrivate *parent_priv;
796         GdkPixbuf *window_icon = NULL;
797         GError *error = NULL;
798
799         GtkSizeGroup *title_size_group;
800         GtkSizeGroup *value_size_group;
801         GtkWidget *window_box;
802         GtkWidget *window_align;
803 #if (GTK_MINOR_VERSION >= 10)
804         GdkAtom deserialize_type;
805 #endif
806         GtkWidget *from_send_hbox;
807         GtkWidget *send_icon;
808         GtkWidget *attachments_label;
809
810         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
811         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
812
813         parent_priv->ui_manager = gtk_ui_manager_new();
814         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
815         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
816
817         /* Add common actions */
818         gtk_action_group_add_actions (action_group,
819                                       modest_msg_edit_action_entries,
820                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
821                                       obj);
822         gtk_action_group_add_actions (action_group,
823                                       hildon2_msg_edit_action_entries,
824                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
825                                       obj);
826         gtk_action_group_add_toggle_actions (action_group,
827                                              modest_msg_edit_toggle_action_entries,
828                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
829                                              obj);
830         gtk_action_group_add_radio_actions (action_group,
831                                             modest_msg_edit_alignment_radio_action_entries,
832                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
833                                             GTK_JUSTIFY_LEFT,
834                                             G_CALLBACK (modest_ui_actions_on_change_justify),
835                                             obj);
836         gtk_action_group_add_radio_actions (action_group,
837                                             modest_msg_edit_priority_action_entries,
838                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
839                                             0,
840                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
841                                             obj);
842         gtk_action_group_add_radio_actions (action_group,
843                                             modest_msg_edit_file_format_action_entries,
844                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
845                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
846                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
847                                             obj);
848         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
849         g_object_unref (action_group);
850
851         /* Load the UI definition */
852         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
853                                          &error);
854         if (error != NULL) {
855                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
856                 g_clear_error (&error);
857         }
858
859         /* Add accelerators */
860         gtk_window_add_accel_group (GTK_WINDOW (obj), 
861                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
862
863         parent_priv->menubar = NULL;
864
865         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
866         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
867
868         /* Note: This ModestPairList* must exist for as long as the picker
869          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
870          * so it can't know how to manage its memory. */ 
871         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
872                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
873                                                           NULL, g_str_equal);
874         modest_selector_picker_set_value_max_chars (MODEST_SELECTOR_PICKER (priv->from_field), MAX_FROM_VALUE);
875         modest_maemo_utils_set_hbutton_layout (title_size_group, NULL, 
876                                                _("mail_va_from"), priv->from_field);
877         hildon_button_set_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5, 1.0, 1.0);
878         hildon_button_set_title_alignment (HILDON_BUTTON (priv->from_field), 0.0, 0.5);
879         hildon_button_set_value_alignment (HILDON_BUTTON (priv->from_field), 1.0, 0.5);
880
881         priv->to_field      = modest_recpt_editor_new ();
882         priv->cc_field      = modest_recpt_editor_new ();
883         priv->bcc_field     = modest_recpt_editor_new ();
884         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->to_field), FALSE);
885         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->cc_field), FALSE);
886         modest_recpt_editor_set_show_abook_button (MODEST_RECPT_EDITOR (priv->bcc_field), FALSE);
887         priv->subject_box = gtk_hbox_new (FALSE, MODEST_MARGIN_NONE);
888         priv->priority_icon = gtk_image_new ();
889         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->priority_icon, FALSE, FALSE, 0);
890         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
891         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
892         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
893         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
894                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
895         gtk_box_pack_start (GTK_BOX (priv->subject_box), priv->subject_field, TRUE, TRUE, 0);
896         priv->attachments_view = modest_attachments_view_new (NULL);
897         modest_attachments_view_set_style (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
898                                            MODEST_ATTACHMENTS_VIEW_STYLE_NO_FOCUS);
899         
900         priv->header_box = gtk_vbox_new (FALSE, 0);
901         
902         to_caption = _create_addressbook_box
903                 (title_size_group, value_size_group,
904                  _("mail_va_to"), priv->to_field);
905         priv->cc_caption = _create_addressbook_box
906                 (title_size_group, value_size_group,
907                  _("mail_va_cc"), priv->cc_field);
908         priv->bcc_caption = _create_addressbook_box
909                 (title_size_group, value_size_group,
910                  _("mail_va_hotfix1"), priv->bcc_field);
911         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
912                                                                _("mail_va_subject"), FALSE, priv->subject_box);
913         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (NULL, NULL,
914                                                                                         _("mail_va_attachment"), 
915                                                                                         FALSE,
916                                                                                         priv->attachments_view,
917                                                                                         HILDON_SIZE_AUTO_WIDTH |
918                                                                                         HILDON_SIZE_AUTO_HEIGHT);
919         attachments_label = modest_maemo_utils_captioned_get_label_widget (priv->attachments_caption);
920         hildon_gtk_widget_set_theme_size (attachments_label, HILDON_SIZE_AUTO_HEIGHT);
921
922
923         priv->send_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
924         send_icon = gtk_image_new_from_icon_name (MODEST_TOOLBAR_ICON_MAIL_SEND, HILDON_ICON_SIZE_FINGER);
925         gtk_container_add (GTK_CONTAINER (priv->send_button), send_icon);
926         gtk_widget_set_size_request (GTK_WIDGET (priv->send_button), 148, -1);
927
928         g_object_unref (title_size_group);
929         g_object_unref (value_size_group);
930
931         from_send_hbox = gtk_hbox_new (FALSE, 0);
932         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->from_field, TRUE, TRUE, 0);
933         gtk_box_pack_start (GTK_BOX (from_send_hbox), priv->send_button, FALSE, FALSE, 0);
934
935         gtk_box_pack_start (GTK_BOX (priv->header_box), from_send_hbox, FALSE, FALSE, 0);
936         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
937         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
938         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
939         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
940         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
941         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
942
943         init_wp_text_view_style ();
944
945         priv->msg_body = modest_wp_text_view_new ();
946         
947
948         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
949         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
950         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
951         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
952 #if (GTK_MINOR_VERSION >= 10)
953         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
954         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
955                                                                        NULL);
956         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
957                                                          deserialize_type, TRUE);
958 #endif
959         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
960
961         priv->find_toolbar = hildon_find_toolbar_new (NULL);
962         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
963
964 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
965
966         priv->pannable = hildon_pannable_area_new ();
967
968         g_object_set (G_OBJECT (priv->pannable), "hscrollbar-policy", GTK_POLICY_NEVER, NULL);
969         
970         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
971         window_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
972         gtk_alignment_set_padding (GTK_ALIGNMENT (window_align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DEFAULT);
973
974         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
975         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
976         gtk_container_add (GTK_CONTAINER (window_align), main_vbox);
977
978         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), window_align);
979         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
980         
981         window_box = gtk_vbox_new (FALSE, 0);
982         gtk_container_add (GTK_CONTAINER(obj), window_box);
983
984         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
985
986         /* Set window icon */
987         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
988         if (window_icon) {
989                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
990                 g_object_unref (window_icon);
991         }       
992 }
993         
994 static void
995 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
996 {
997         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
998
999         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
1000             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1001                                            priv->clipboard_change_handler_id))
1002                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
1003                                              priv->clipboard_change_handler_id);
1004         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
1005             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1006                                            priv->default_clipboard_change_handler_id))
1007                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
1008                                              priv->default_clipboard_change_handler_id);
1009
1010         if (priv->account_removed_handler_id && 
1011             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
1012                                            priv->account_removed_handler_id))
1013                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
1014                                            priv->account_removed_handler_id);
1015 }
1016
1017 static void
1018 modest_msg_edit_window_finalize (GObject *obj)
1019 {
1020         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1021         
1022         /* Sanity check: shouldn't be needed, the window mgr should
1023            call this function before */
1024         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
1025
1026         if (priv->font_dialog != NULL) {
1027                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
1028         }
1029
1030         if (priv->clipboard_text != NULL) {
1031                 g_free (priv->clipboard_text);
1032                 priv->clipboard_text = NULL;
1033         }
1034         
1035         if (priv->draft_msg != NULL) {
1036                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
1037                 if (TNY_IS_HEADER (header)) {
1038                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1039                         modest_window_mgr_unregister_header (mgr, header);
1040                 }
1041                 g_object_unref (priv->draft_msg);
1042                 priv->draft_msg = NULL;
1043         }
1044         if (priv->outbox_msg != NULL) {
1045                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
1046                 if (TNY_IS_HEADER (header)) {
1047                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
1048                         modest_window_mgr_unregister_header (mgr, header);
1049                 }
1050                 g_object_unref (priv->outbox_msg);
1051                 priv->outbox_msg = NULL;
1052         }
1053         if (priv->correct_scroll_idle > 0) {
1054                 g_source_remove (priv->correct_scroll_idle);
1055                 priv->correct_scroll_idle = 0;
1056         }
1057         if (priv->scroll_drag_timeout_id > 0) {
1058                 g_source_remove (priv->scroll_drag_timeout_id);
1059                 priv->scroll_drag_timeout_id = 0;
1060         }
1061         if (priv->clipboard_owner_idle > 0) {
1062                 g_source_remove (priv->clipboard_owner_idle);
1063                 priv->clipboard_owner_idle = 0;
1064         }
1065         if (priv->original_account_name)
1066                 g_free (priv->original_account_name);
1067         if (priv->original_mailbox)
1068                 g_free (priv->original_mailbox);
1069         g_free (priv->msg_uid);
1070         g_free (priv->last_search);
1071         g_free (priv->references);
1072         g_free (priv->in_reply_to);
1073         g_object_unref (priv->faces_model);
1074         g_object_unref (priv->sizes_model);
1075         g_object_unref (priv->attachments);
1076         g_object_unref (priv->images);
1077
1078         /* This had to stay alive for as long as the picker that used it: */
1079         modest_pair_list_free (priv->from_field_protos);
1080         
1081         G_OBJECT_CLASS(parent_class)->finalize (obj);
1082 }
1083
1084 static void
1085 pixbuf_size_prepared (GdkPixbufLoader *loader,
1086                       gint width,
1087                       gint height,
1088                       ModestMsgEditWindow *self)
1089 {
1090         gint new_height, new_width;
1091         gboolean set_size;
1092         
1093         new_height = height;
1094         new_width = width;
1095         set_size = FALSE;
1096
1097         if (width > IMAGE_MAX_WIDTH) {
1098                 new_height = height * IMAGE_MAX_WIDTH / width;
1099                 new_width = IMAGE_MAX_WIDTH;
1100         }
1101
1102         gdk_pixbuf_loader_set_size (loader, new_width, new_height);
1103 }
1104
1105 static GdkPixbuf *
1106 pixbuf_from_stream (TnyStream *stream,
1107                     const gchar *mime_type,
1108                     guint64 *stream_size,
1109                     ModestMsgEditWindow *self)
1110 {
1111         GdkPixbufLoader *loader;
1112         GdkPixbuf *pixbuf;
1113         guint64 size;
1114         GError *error = NULL;
1115
1116         size = 0;
1117
1118         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1119
1120         if (loader == NULL) {
1121                 if (stream_size)
1122                         *stream_size = 0;
1123                 return NULL;
1124         }
1125         g_signal_connect (G_OBJECT (loader), "size-prepared", G_CALLBACK (pixbuf_size_prepared), self);
1126
1127         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), TRUE);
1128
1129         tny_stream_reset (TNY_STREAM (stream));
1130         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1131                 unsigned char read_buffer[128];
1132                 gint readed;
1133                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
1134                 size += readed;
1135                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1136                         break;
1137                 }
1138                 /* Allow some UI responsiveness */
1139                 while (gtk_events_pending ())
1140                         gtk_main_iteration ();
1141         }
1142         hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), FALSE);
1143
1144         gdk_pixbuf_loader_close (loader, &error);
1145
1146         if (error)
1147                 g_error_free (error);
1148         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1149         if (pixbuf) 
1150                 g_object_ref (pixbuf);
1151         g_object_unref (loader);
1152
1153         if (!pixbuf)
1154                 return NULL;
1155
1156         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1157                 GdkPixbuf *new_pixbuf;
1158                 gint new_height;
1159                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1160                         gdk_pixbuf_get_width (pixbuf);
1161                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1162                 g_object_unref (pixbuf);
1163                 pixbuf = new_pixbuf;
1164         }
1165
1166         if (stream_size)
1167                 *stream_size = size;
1168
1169         return pixbuf;
1170 }
1171
1172 static void
1173 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1174 {
1175         ModestMsgEditWindowPrivate *priv;
1176         TnyIterator *iter;
1177
1178         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1179
1180         g_object_ref (self);
1181         for (iter = tny_list_create_iterator (attachments);
1182              !tny_iterator_is_done (iter);
1183              tny_iterator_next (iter)) {
1184                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1185                 const gchar *cid = tny_mime_part_get_content_id (part);
1186                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1187                 if ((cid != NULL)&&(mime_type != NULL)) {
1188                         guint64 stream_size;
1189                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1190                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, self);
1191
1192
1193                         g_object_unref (stream);
1194
1195                         if (pixbuf != NULL) {
1196                                 priv->images_count ++;
1197                                 priv->images_size += stream_size;
1198                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1199                                 g_object_unref (pixbuf);
1200                         }
1201                 }
1202                 g_object_unref (part);
1203         }
1204         g_object_unref (iter);
1205         g_object_unref (self);
1206 }
1207
1208 static void
1209 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1210 {
1211         TnyMimePart *parent = NULL;
1212         const gchar *content_type = NULL;
1213         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1214
1215         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1216
1217         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1218                 parent = g_object_ref (msg);
1219         } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1220                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1221                 TnyIterator *iter;
1222
1223                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1224                 iter = tny_list_create_iterator (parts);
1225                 while (!tny_iterator_is_done (iter)) {
1226                         TnyMimePart *part;
1227                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1228                         content_type = tny_mime_part_get_content_type (part);
1229                         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1230                                 parent = part;
1231                                 break;
1232                         } else {
1233                                 g_object_unref (part);
1234                         }
1235                         tny_iterator_next (iter);
1236                 }
1237                 g_object_unref (iter);
1238                 g_object_unref (parts);
1239         }
1240
1241         if (parent != NULL) {
1242                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1243                 TnyIterator *iter;
1244
1245                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1246                 iter = tny_list_create_iterator (parts);
1247                 while (!tny_iterator_is_done (iter)) {
1248                         TnyMimePart *part;
1249                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1250                         content_type = tny_mime_part_get_content_type (part);
1251                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1252                                 tny_list_prepend (priv->images, (GObject *) part);
1253                         } 
1254                         g_object_unref (part);
1255                         tny_iterator_next (iter);
1256                 }
1257                 g_object_unref (iter);
1258                 g_object_unref (parts);
1259                 g_object_unref (parent);
1260         }
1261 }
1262
1263 static void
1264 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1265 {
1266         TnyIterator *iter;
1267         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1268
1269         for (iter = tny_list_create_iterator (attachments) ; 
1270              !tny_iterator_is_done (iter);
1271              tny_iterator_next (iter)) {
1272                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1273                 const gchar *cid = tny_mime_part_get_content_id (part);
1274                 if (cid != NULL) {
1275                         char *invalid = NULL;
1276                         gint int_cid = strtol (cid, &invalid, 10);
1277                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1278                                 priv->next_cid = int_cid + 1;
1279                         }
1280                 }
1281                 g_object_unref (part);
1282         }
1283         g_object_unref (iter);
1284 }
1285
1286 static void
1287 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1288 {
1289         TnyHeader *header;
1290         gchar *to, *cc, *bcc, *subject;
1291         gchar *body;
1292         ModestMsgEditWindowPrivate *priv;
1293         ModestWindowPrivate *parent_priv;
1294         GtkTextIter iter;
1295         TnyHeaderFlags priority_flags;
1296         TnyFolder *msg_folder;
1297         gboolean is_html = FALSE;
1298         gboolean field_view_set;
1299         
1300         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1301         g_return_if_fail (TNY_IS_MSG (msg));
1302
1303         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1304         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1305
1306         header = tny_msg_get_header (msg);
1307         to      = tny_header_dup_to (header);
1308         cc      = tny_header_dup_cc (header);
1309         bcc     = tny_header_dup_bcc (header);
1310         subject = tny_header_dup_subject (header);
1311
1312         modest_tny_msg_get_references (TNY_MSG (msg), NULL, &(priv->references), &(priv->in_reply_to));
1313         priority_flags = tny_header_get_priority (header);
1314
1315         if (to)
1316                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
1317
1318         field_view_set = TRUE;
1319         if (cc) {
1320                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
1321                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1322                 gtk_widget_show (priv->cc_caption);
1323         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1324                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1325                 gtk_widget_hide (priv->cc_caption);
1326                 field_view_set = FALSE;
1327         }
1328         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1329
1330         field_view_set = TRUE;
1331         if (bcc) {
1332                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1333                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1334                 gtk_widget_show (priv->bcc_caption);
1335         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1336                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1337                 gtk_widget_hide (priv->bcc_caption);
1338                 field_view_set = FALSE;
1339         }
1340         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1341
1342
1343         if (subject)
1344                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1345         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1346                                                    priority_flags);
1347
1348         update_window_title (self);
1349
1350         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1351         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1352
1353         if ((body == NULL)||(body[0] == '\0')) {
1354                 g_free (body);
1355                 body = modest_text_utils_convert_to_html ("");
1356                 is_html = FALSE;
1357         }
1358         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1359         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1360                                             (gchar *) body,
1361                                             strlen (body));
1362         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1363         g_free (body);
1364
1365         /* Add attachments to the view */
1366         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1367         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1368         if (tny_list_get_length (priv->attachments) == 0) {
1369                 gtk_widget_hide (priv->attachments_caption);
1370         } else {
1371                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1372                 gtk_widget_show_all (priv->attachments_caption);
1373         }
1374         get_related_images (self, msg);
1375         update_next_cid (self, priv->attachments);
1376         update_next_cid (self, priv->images);
1377         replace_with_images (self, priv->images);
1378
1379         if (preserve_is_rich && !is_html) {
1380                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1381         /* Get the default format required from configuration */
1382         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1383                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1384         }
1385
1386         /* Set the default focus depending on having already a To: field or not */
1387         if ((!to)||(*to == '\0')) {
1388                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1389         } else {
1390                 gtk_widget_grab_focus (priv->msg_body);
1391         }
1392
1393         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1394
1395         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1396         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1397
1398         modest_msg_edit_window_set_modified (self, FALSE);
1399
1400         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1401         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1402         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1403         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1404
1405         if (priv->msg_uid) {
1406                 g_free (priv->msg_uid);
1407                 priv->msg_uid = NULL;
1408         }
1409
1410         /* we should set a reference to the incoming message if it is a draft */
1411         msg_folder = tny_msg_get_folder (msg);
1412         if (msg_folder) {               
1413                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1414                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1415                         if (type == TNY_FOLDER_TYPE_INVALID)
1416                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1417                         
1418                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1419                                 priv->draft_msg = g_object_ref(msg);
1420                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1421                                 priv->outbox_msg = g_object_ref(msg);
1422                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1423                 }
1424                 g_object_unref (msg_folder);
1425         }
1426
1427         g_free (to);
1428         g_free (subject);
1429         g_free (cc);
1430         g_free (bcc);
1431 }
1432
1433
1434 static void
1435 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1436 {
1437         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1438         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1439         GtkWidget *placeholder;
1440         GtkWidget *tool_item;
1441         gint insert_index;
1442         gchar size_text[5];
1443         gint size_index;
1444         gint font_index;
1445         GtkWidget *sizes_menu;
1446         GtkWidget *fonts_menu;
1447         gchar *markup;
1448         GtkWidget *arrow;
1449         GtkWidget *hbox;
1450
1451         /* Toolbar */
1452         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1453         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1454         gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1455         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1456
1457         /* Font color placeholder */
1458         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1459         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1460
1461         /* font color */
1462         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1463         priv->font_color_button = hildon_color_button_new ();
1464         gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1465         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1466         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1467         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1468         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1469         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1470         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1471         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1472                                   "notify::color", 
1473                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1474                                   window);
1475
1476         /* Font size and face placeholder */
1477         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1478         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1479         /* font_size */
1480         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1481         priv->size_tool_button_label = gtk_label_new (NULL);
1482         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1483         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1484                               size_text, "</span>", NULL);
1485         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1486         gtk_misc_set_alignment (GTK_MISC (priv->size_tool_button_label), 1.0, 0.5);
1487         g_free (markup);
1488         hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1489         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1490         gtk_box_pack_start (GTK_BOX (hbox), priv->size_tool_button_label, TRUE, TRUE, 0);
1491         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1492         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1493         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1494         gtk_widget_set_sensitive (arrow, FALSE);
1495         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1496         sizes_menu = gtk_menu_new ();
1497         priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1498         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1499                 GtkTreeIter iter;
1500
1501                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1502                 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1503
1504                 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter, 
1505                                     0, size_text,
1506                                     -1);
1507
1508                 if (wp_font_size[size_index] == 12)
1509                         priv->current_size_index = size_index;
1510                                         
1511         }
1512
1513         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1514         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1515         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1516         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1517         priv->font_size_toolitem = tool_item;
1518
1519         /* font face */
1520         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1521         priv->font_tool_button_label = gtk_label_new (NULL);
1522         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1523         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1524         gtk_misc_set_alignment (GTK_MISC (priv->font_tool_button_label), 1.0, 0.5);
1525         g_free(markup);
1526         hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1527         hbox = gtk_hbox_new (MODEST_MARGIN_DEFAULT, FALSE);
1528         gtk_box_pack_start (GTK_BOX (hbox), priv->font_tool_button_label, TRUE, TRUE, 0);
1529         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1530         gtk_misc_set_alignment (GTK_MISC (arrow), 0.0, 0.5);
1531         gtk_box_pack_start (GTK_BOX (hbox), arrow, TRUE, TRUE, 0);
1532         gtk_widget_set_sensitive (arrow, FALSE);
1533         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), hbox);
1534         fonts_menu = gtk_menu_new ();
1535         priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1536         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1537                 GtkTreeIter iter;
1538
1539                 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1540
1541                 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter, 
1542                                     0, wp_get_font_name (font_index),
1543                                     -1);
1544
1545                 if (font_index == DEFAULT_FONT)
1546                         priv->current_face_index = font_index;
1547         }
1548         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1549         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1550         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1551         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1552         priv->font_face_toolitem = tool_item;
1553
1554         /* Set expand and homogeneous for remaining items */
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         } else {
2640                 g_object_ref (att_list);
2641         }
2642
2643         if (tny_list_get_length (att_list) == 0) {
2644                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2645         } else {
2646                 gboolean dialog_response;
2647                 gchar *message = NULL;
2648                 gchar *filename = NULL;
2649
2650                 if (tny_list_get_length (att_list) == 1) {
2651                         TnyMimePart *part;
2652                         iter = tny_list_create_iterator (att_list);
2653                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2654                         g_object_unref (iter);
2655                         if (TNY_IS_MSG (part)) {
2656                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2657                                 if (header) {
2658                                         filename = tny_header_dup_subject (header);
2659                                         g_object_unref (header);
2660                                 }
2661                                 if (filename == NULL) {
2662                                         filename = g_strdup (_("mail_va_no_subject"));
2663                                 }
2664                         } else {
2665                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2666                         }
2667                         g_object_unref (part);
2668                 } else {
2669                         filename = g_strdup ("");
2670                 }
2671                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2672                                                     "emev_nc_delete_attachments",
2673                                                     tny_list_get_length (att_list)), filename);
2674                 g_free (filename);
2675
2676                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2677                                                                            message);
2678                 g_free (message);
2679
2680                 if (dialog_response != GTK_RESPONSE_OK) {
2681                         g_object_unref (att_list);
2682                         return;
2683                 }
2684
2685                 for (iter = tny_list_create_iterator (att_list);
2686                      !tny_iterator_is_done (iter);
2687                      tny_iterator_next (iter)) {
2688                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2689                         const gchar *att_id;
2690                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2691
2692                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2693                                                                    mime_part);
2694                         if (tny_list_get_length (priv->attachments) == 0)
2695                                 gtk_widget_hide (priv->attachments_caption);
2696                         att_id = tny_mime_part_get_content_id (mime_part);
2697                         if (att_id != NULL)
2698                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2699                                                                  att_id);
2700                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2701                         g_object_unref (mime_part);
2702                 }
2703                 g_object_unref (iter);
2704         }
2705
2706         g_object_unref (att_list);
2707
2708         /* if the last attachment has been removed, focus the Subject: field */
2709         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view)))
2710                 gtk_widget_grab_focus (priv->subject_field);
2711 }
2712
2713 static void
2714 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2715                                             gpointer userdata)
2716 {
2717         ModestMsgEditWindowPrivate *priv;
2718         GdkColor *new_color;
2719         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2720         
2721 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2722         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2723 #else 
2724         GdkColor col;
2725         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2726         new_color = &col;
2727 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2728
2729         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2730         
2731         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2732
2733 }
2734
2735 static void
2736 font_size_clicked (GtkToolButton *button,
2737                    ModestMsgEditWindow *window)
2738 {
2739         ModestMsgEditWindowPrivate *priv;
2740         GtkWidget *selector, *dialog;
2741         
2742         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2743
2744         selector = hildon_touch_selector_new ();
2745         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2746         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2747
2748         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2749         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2750         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2751
2752         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2753                 gint new_index;
2754                 gchar *size_text;
2755                 gchar *markup;
2756                 WPTextBufferFormat format;
2757
2758                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2759
2760                 memset (&format, 0, sizeof (format));
2761                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2762
2763                 format.cs.font_size = TRUE;
2764                 format.cs.text_position = TRUE;
2765                 format.cs.font = TRUE;
2766                 format.font_size = new_index;
2767 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2768
2769                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2770                                                    GINT_TO_POINTER (new_index)))
2771                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2772                 
2773                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2774                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2775                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2776                                       size_text, "</span>", NULL);
2777                 g_free (size_text);
2778                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2779                 g_free (markup);
2780
2781         }
2782         gtk_widget_destroy (dialog);
2783
2784         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2785
2786 }
2787
2788 static void
2789 font_face_clicked (GtkToolButton *button,
2790                    ModestMsgEditWindow *window)
2791 {
2792         ModestMsgEditWindowPrivate *priv;
2793         GtkWidget *selector, *dialog;
2794         GtkCellRenderer *renderer;
2795         
2796         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2797
2798         selector = hildon_touch_selector_new ();
2799         renderer = gtk_cell_renderer_text_new ();
2800         g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2801         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2802                                              renderer, "family", 0, "text", 0, NULL);
2803         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2804
2805         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2806         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2807         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2808
2809         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2810                 gint new_font_index;
2811                 GtkTreePath *path;
2812                 GtkTreeIter iter;
2813
2814                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2815                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2816                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2817                         gchar *face_name;
2818                         gchar *markup;
2819
2820                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2821
2822                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2823                                                            GINT_TO_POINTER(new_font_index)))
2824                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2825
2826                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2827                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2828
2829                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2830                         g_free (face_name);
2831                         g_free (markup);
2832                 }
2833                 gtk_tree_path_free (path);
2834
2835         }
2836         gtk_widget_destroy (dialog);
2837
2838         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2839
2840 }
2841
2842 void
2843 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2844                                 gboolean show)
2845 {
2846         ModestMsgEditWindowPrivate *priv = NULL;
2847         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2848
2849         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2850         if (!priv->update_caption_visibility)
2851                 return;
2852
2853         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2854         if (show)
2855                 gtk_widget_show (priv->cc_caption);
2856         else
2857                 gtk_widget_hide (priv->cc_caption);
2858
2859         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2860 }
2861
2862 void
2863 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2864                                  gboolean show)
2865 {
2866         ModestMsgEditWindowPrivate *priv = NULL;
2867         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2868
2869         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2870         if (!priv->update_caption_visibility)
2871                 return;
2872
2873         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2874         if (show)
2875                 gtk_widget_show (priv->bcc_caption);
2876         else
2877                 gtk_widget_hide (priv->bcc_caption);
2878
2879         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2880 }
2881
2882 static void
2883 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2884                                          ModestRecptEditor *editor)
2885 {
2886         ModestMsgEditWindowPrivate *priv;
2887
2888         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2889         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2890         
2891         /* we check for low-mem; in that case, show a warning, and don't allow
2892          * for the addressbook
2893          */
2894         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2895                 return;
2896
2897         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2898
2899         if (editor == NULL) {
2900                 GtkWidget *view_focus;
2901                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2902
2903                 /* This code should be kept in sync with ModestRecptEditor. The
2904                    textview inside the recpt editor is the one that really gets the
2905                    focus. As it's inside a scrolled window, and this one inside the
2906                    hbox recpt editor inherits from, we'll need to go up in the 
2907                    hierarchy to know if the text view is part of the recpt editor
2908                    or if it's a different text entry */
2909
2910                 if (gtk_widget_get_parent (view_focus)) {
2911                         GtkWidget *first_parent;
2912
2913                         first_parent = gtk_widget_get_parent (view_focus);
2914                         if (gtk_widget_get_parent (first_parent) && 
2915                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2916                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2917                         }
2918                 }
2919
2920                 if (editor == NULL)
2921                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2922
2923         }
2924
2925         modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2926 }
2927
2928 void
2929 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2930 {
2931         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2932
2933         modest_msg_edit_window_open_addressbook (window, NULL);
2934 }
2935
2936 static void
2937 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2938                                      gboolean show_toolbar)
2939 {
2940         ModestWindowPrivate *parent_priv;
2941         ModestMsgEditWindowPrivate *priv;
2942
2943         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2944         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2945         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2946
2947         /* We can not just use the code of
2948            modest_msg_edit_window_setup_toolbar because it has a
2949            mixture of both initialization and creation code. */
2950         if (show_toolbar) {
2951                 gint current_format;
2952                 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2953                         ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2954                 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2955                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2956                 } else {
2957                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2958                 }
2959         } else {
2960                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2961         }
2962 }
2963
2964 void
2965 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2966                                            TnyHeaderFlags priority_flags)
2967 {
2968         ModestMsgEditWindowPrivate *priv;
2969         ModestWindowPrivate *parent_priv;
2970
2971         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2972
2973         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2974         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2975
2976         if (priv->priority_flags != priority_flags) {
2977                 GtkAction *priority_action = NULL;
2978
2979                 priv->priority_flags = priority_flags;
2980
2981                 switch (priority_flags) {
2982                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2983                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2984                                                       MODEST_HEADER_ICON_HIGH, 
2985                                                       HILDON_ICON_SIZE_SMALL);
2986                         gtk_widget_show (priv->priority_icon);
2987                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2988                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2989                         break;
2990                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2991                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2992                                                       MODEST_HEADER_ICON_LOW,
2993                                                       HILDON_ICON_SIZE_SMALL);
2994                         gtk_widget_show (priv->priority_icon);
2995                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2996                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2997                         break;
2998                 default:
2999                         gtk_widget_hide (priv->priority_icon);
3000                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3001                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3002                         break;
3003                 }
3004                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3005                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3006         }
3007         gtk_widget_queue_resize (priv->subject_box);
3008 }
3009
3010 void
3011 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3012                                         gint file_format)
3013 {
3014         ModestMsgEditWindowPrivate *priv;
3015         ModestWindowPrivate *parent_priv;
3016         gint current_format;
3017
3018         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3019
3020         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3021         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3022
3023         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3024                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3025
3026         gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3027
3028         if (parent_priv->toolbar) {
3029                 if (file_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
3030                         gtk_widget_hide (parent_priv->toolbar);
3031                 } else {
3032                         gtk_widget_show (parent_priv->toolbar);
3033                 }
3034         }
3035
3036         if (current_format != file_format) {
3037                 switch (file_format) {
3038                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3039                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3040                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3041                         break;
3042                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3043                 {
3044                         GtkWidget *dialog;
3045                         gint response;
3046                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3047                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3048                         gtk_widget_destroy (dialog);
3049                         if (response == GTK_RESPONSE_OK) {
3050                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3051                                 if (parent_priv->toolbar) gtk_widget_hide (parent_priv->toolbar);
3052                         } else {
3053                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3054                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3055                         }
3056                 }
3057                         break;
3058                 }
3059                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3060                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3061                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3062         }
3063 }
3064
3065 void
3066 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3067 {
3068         GtkWidget *dialog;
3069         ModestMsgEditWindowPrivate *priv;
3070         WPTextBufferFormat oldfmt, fmt;
3071         gint old_position = 0;
3072         gint response = 0;
3073         gint position = 0;
3074         gint font_size;
3075         GdkColor *color = NULL;
3076         gboolean bold, bold_set, italic, italic_set;
3077         gboolean underline, underline_set;
3078         gboolean strikethrough, strikethrough_set;
3079         gboolean position_set;
3080         gboolean font_size_set, font_set, color_set;
3081         gchar *font_name;
3082
3083         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3084         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3085         
3086         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3087         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3088                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
3089
3090         /* First we get the currently selected font information */
3091         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3092
3093         switch (oldfmt.text_position) {
3094         case TEXT_POSITION_NORMAL:
3095                 old_position = 0;
3096                 break;
3097         case TEXT_POSITION_SUPERSCRIPT:
3098                 old_position = 1;
3099                 break;
3100         default:
3101                 old_position = -1;
3102                 break;
3103         }
3104
3105         g_object_set (G_OBJECT (dialog),
3106                       "bold", oldfmt.bold != FALSE,
3107                       "bold-set", !oldfmt.cs.bold,
3108                       "underline", oldfmt.underline != FALSE,
3109                       "underline-set", !oldfmt.cs.underline,
3110                       "italic", oldfmt.italic != FALSE,
3111                       "italic-set", !oldfmt.cs.italic,
3112                       "strikethrough", oldfmt.strikethrough != FALSE,
3113                       "strikethrough-set", !oldfmt.cs.strikethrough,
3114                       "color", &oldfmt.color,
3115                       "color-set", !oldfmt.cs.color,
3116                       "size", wp_font_size[oldfmt.font_size],
3117                       "size-set", !oldfmt.cs.font_size,
3118                       "position", old_position,
3119                       "position-set", !oldfmt.cs.text_position,
3120                       "family", wp_get_font_name (oldfmt.font),
3121                       "family-set", !oldfmt.cs.font,
3122                       NULL);
3123
3124         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
3125                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
3126         gtk_widget_show_all (dialog);
3127         priv->font_dialog = dialog;
3128         response = gtk_dialog_run (GTK_DIALOG (dialog));
3129         priv->font_dialog = NULL;
3130         if (response == GTK_RESPONSE_OK) {
3131
3132                 g_object_get( dialog,
3133                               "bold", &bold,
3134                               "bold-set", &bold_set,
3135                               "underline", &underline,
3136                               "underline-set", &underline_set,
3137                               "italic", &italic,
3138                               "italic-set", &italic_set,
3139                               "strikethrough", &strikethrough,
3140                               "strikethrough-set", &strikethrough_set,
3141                               "color", &color,
3142                               "color-set", &color_set,
3143                               "size", &font_size,
3144                               "size-set", &font_size_set,
3145                               "family", &font_name,
3146                               "family-set", &font_set,
3147                               "position", &position,
3148                               "position-set", &position_set,
3149                               NULL );
3150                 
3151         }       
3152
3153         if (response == GTK_RESPONSE_OK) {
3154                 memset(&fmt, 0, sizeof(fmt));
3155                 if (bold_set) {
3156                         fmt.bold = bold;
3157                         fmt.cs.bold = TRUE;
3158                 }
3159                 if (italic_set) {
3160                         fmt.italic = italic;
3161                         fmt.cs.italic = TRUE;
3162                 }
3163                 if (underline_set) {
3164                         fmt.underline = underline;
3165                         fmt.cs.underline = TRUE;
3166                 }
3167                 if (strikethrough_set) {
3168                         fmt.strikethrough = strikethrough;
3169                         fmt.cs.strikethrough = TRUE;
3170                 }
3171                 if (position_set) {
3172                         fmt.text_position =
3173                                 ( position == 0 )
3174                                 ? TEXT_POSITION_NORMAL
3175                                 : ( ( position == 1 )
3176                                     ? TEXT_POSITION_SUPERSCRIPT
3177                                     : TEXT_POSITION_SUBSCRIPT );
3178                         fmt.cs.text_position = TRUE;
3179                         fmt.font_size = oldfmt.font_size;
3180                 }
3181                 if (color_set) {
3182                         fmt.color = *color;
3183                         fmt.cs.color = TRUE;
3184                 }
3185                 if (font_set) {
3186                         fmt.font = wp_get_font_index(font_name,
3187                                                      DEFAULT_FONT);
3188                         fmt.cs.font = TRUE;
3189                 }
3190                 g_free(font_name);
3191                 if (font_size_set) {
3192                         fmt.cs.font_size = TRUE;
3193                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3194                 }
3195                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3196                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3197         }
3198         gtk_widget_destroy (dialog);
3199         
3200         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3201 }
3202
3203 void
3204 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3205 {
3206         ModestMsgEditWindowPrivate *priv;
3207
3208         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3209         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3210         
3211         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3212
3213         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3214         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3215 }
3216
3217 void
3218 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3219 {
3220         ModestMsgEditWindowPrivate *priv;
3221
3222         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3223         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3224         
3225         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3226
3227         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3228         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3229
3230 }
3231
3232 static void  
3233 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3234 {
3235         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3236
3237         priv->can_undo = can_undo;
3238 }
3239
3240 static void  
3241 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3242 {
3243         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3244
3245         priv->can_redo = can_redo;
3246 }
3247
3248 gboolean            
3249 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3250 {
3251         ModestMsgEditWindowPrivate *priv;
3252         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3253         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3254
3255         return priv->can_undo;
3256 }
3257
3258 gboolean            
3259 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3260 {
3261         ModestMsgEditWindowPrivate *priv;
3262         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3263         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3264
3265         return priv->can_redo;
3266 }
3267
3268
3269 static void
3270 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3271 {
3272         GtkTextIter iter;
3273         GtkTextIter match_start, match_end;
3274
3275         if (image_id == NULL)
3276                 return;
3277
3278         gtk_text_buffer_get_start_iter (buffer, &iter);
3279
3280         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3281                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3282                 GSList *node;
3283                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3284                         GtkTextTag *tag = (GtkTextTag *) node->data;
3285                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3286                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3287                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3288                                         gint offset;
3289                                         offset = gtk_text_iter_get_offset (&match_start);
3290                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3291                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3292                                 }
3293                         }
3294                 }
3295                 gtk_text_iter_forward_char (&iter);
3296         }
3297 }
3298
3299 gboolean
3300 message_is_empty (ModestMsgEditWindow *window)
3301 {
3302         ModestMsgEditWindowPrivate *priv = NULL;
3303
3304         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3305         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3306
3307         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3308          * so we can ignore markup.
3309          */
3310         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3311         gint count = 0;
3312         if (buf)
3313                 count = gtk_text_buffer_get_char_count (buf);
3314
3315         return count == 0;
3316 }
3317
3318 static gboolean
3319 msg_body_focus (GtkWidget *focus,
3320                 GdkEventFocus *event,
3321                 gpointer userdata)
3322 {
3323         
3324         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3325         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3326         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3327         return FALSE;
3328 }
3329
3330 static void
3331 recpt_field_changed (GtkTextBuffer *buffer,
3332                   ModestMsgEditWindow *editor)
3333 {
3334         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3335         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3336 }
3337
3338 static void
3339 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3340 {
3341         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3342         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3343 }
3344
3345 void
3346 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3347                                      gboolean modified)
3348 {
3349         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3350         GtkTextBuffer *buffer;
3351
3352         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3353         gtk_text_buffer_set_modified (buffer, modified);
3354         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3355         gtk_text_buffer_set_modified (buffer, modified);
3356         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3357         gtk_text_buffer_set_modified (buffer, modified);
3358         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3359 }
3360
3361 gboolean
3362 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3363 {
3364         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3365         const char *account_name;
3366         GtkTextBuffer *buffer;
3367
3368         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3369         if (gtk_text_buffer_get_modified (buffer))
3370                 return TRUE;
3371         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3372         if (gtk_text_buffer_get_modified (buffer))
3373                 return TRUE;
3374         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3375         if (gtk_text_buffer_get_modified (buffer))
3376                 return TRUE;
3377         if (gtk_text_buffer_get_modified (priv->text_buffer))
3378                 return TRUE;
3379
3380         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3381         if (priv->original_mailbox) {
3382                 if (!account_name || strcmp (account_name, priv->original_mailbox))
3383                         return TRUE;
3384         } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3385                 return TRUE;
3386         }
3387
3388         return FALSE;
3389 }
3390
3391
3392
3393
3394 gboolean
3395 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3396 {
3397         ModestMsgEditWindowPrivate *priv = NULL;
3398         
3399         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3400         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3401
3402         /* check if there's no recipient added */
3403         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3404             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3405             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3406                 /* no recipient contents, then select contacts */
3407                 modest_msg_edit_window_open_addressbook (window, NULL);
3408                 return FALSE;
3409         }
3410
3411         g_object_ref (window);
3412         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3413                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3414                 g_object_unref (window);
3415                 return FALSE;
3416         }
3417         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3418                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3419                 g_object_unref (window);
3420                 return FALSE;
3421         }
3422         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3423                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3424                 g_object_unref (window);
3425                 return FALSE;
3426         }
3427
3428         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3429             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3430                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3431         g_object_unref (window);
3432
3433         return TRUE;
3434
3435 }
3436
3437 static void
3438 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3439                                                ModestMsgEditWindow *window)
3440 {
3441         modest_msg_edit_window_offer_attach_file (window);
3442 }
3443
3444 const gchar *
3445 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3446 {
3447         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3448
3449         return priv->clipboard_text;
3450 }
3451
3452 static void
3453 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3454                                                GdkEvent *event,
3455                                                ModestMsgEditWindow *window)
3456 {
3457         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3458         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3459         gchar *text = NULL;
3460
3461         /* It could happen that the window was already closed */
3462         if (!GTK_WIDGET_VISIBLE (window))
3463                 return;
3464
3465         g_object_ref (window);
3466         text = gtk_clipboard_wait_for_text (selection_clipboard);
3467
3468         if (priv->clipboard_text != NULL) {
3469                 g_free (priv->clipboard_text);
3470         }
3471         priv->clipboard_text = text;
3472
3473         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3474
3475         g_object_unref (window);
3476 }
3477
3478 static gboolean clipboard_owner_change_idle (gpointer userdata)
3479 {
3480         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3481         ModestMsgEditWindowPrivate *priv;
3482
3483         gdk_threads_enter ();
3484         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3485         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3486
3487         priv->clipboard_owner_idle = 0;
3488         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3489         gdk_threads_leave ();
3490
3491         return FALSE;
3492 }
3493
3494 static void
3495 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3496 {
3497         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3498         if (priv->clipboard_owner_idle == 0) {
3499                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3500                                                               clipboard_owner_change_idle, 
3501                                                               g_object_ref (window),
3502                                                               g_object_unref);
3503         }
3504 }
3505
3506 static void 
3507 subject_field_move_cursor (GtkEntry *entry,
3508                            GtkMovementStep step,
3509                            gint a1,
3510                            gboolean a2,
3511                            gpointer window)
3512 {
3513         /* It could happen that the window was already closed */
3514         if (!GTK_WIDGET_VISIBLE (window))
3515                 return;
3516
3517         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3518 }
3519
3520 static void 
3521 update_window_title (ModestMsgEditWindow *window)
3522 {
3523         ModestMsgEditWindowPrivate *priv = NULL;
3524         const gchar *subject;
3525
3526         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3527         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3528         if (subject == NULL || subject[0] == '\0')
3529                 subject = _("mail_va_new_email");
3530
3531         gtk_window_set_title (GTK_WINDOW (window), subject);
3532
3533 }
3534
3535
3536 static void  
3537 body_insert_text (GtkTextBuffer *buffer, 
3538                   GtkTextIter *location,
3539                   gchar *text,
3540                   gint len,
3541                   ModestMsgEditWindow *window)
3542 {
3543         GtkTextIter end_iter;
3544         gint offset;
3545
3546         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3547
3548         offset = gtk_text_iter_get_offset (&end_iter);
3549
3550         if (offset + len > MAX_BODY_LENGTH) {
3551                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3552                 if (offset < MAX_BODY_LENGTH)
3553                 {
3554                         gchar *result;
3555
3556                         /* Prevent endless recursion */
3557                         result = g_strndup (text, MAX_BODY_LENGTH - offset);
3558                         g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3559                         g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3560                                                (gpointer) result, (gpointer) MAX_BODY_LENGTH - offset,
3561                                                (gpointer) window);
3562                         g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3563                 }
3564
3565         }
3566         if (offset + len > MAX_BODY_LENGTH) {
3567                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3568                                                 _CS("ckdg_ib_maximum_characters_reached"));
3569         }
3570 }
3571
3572 static void  
3573 subject_field_changed (GtkEditable *editable, 
3574                        ModestMsgEditWindow *window)
3575 {
3576         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3577         update_window_title (window);
3578         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3579         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3580         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3581 }
3582 static void  
3583 subject_field_insert_text (GtkEditable *editable, 
3584                            gchar *new_text,
3585                            gint new_text_length,
3586                            gint *position,
3587                            ModestMsgEditWindow *window)
3588 {
3589         GString *result = g_string_new ("");
3590         gchar *current;
3591         gint result_len = 0;
3592         const gchar *entry_text = NULL;
3593         gint old_length;
3594
3595         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3596         old_length = g_utf8_strlen (entry_text, -1);
3597
3598         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3599                 gunichar c = g_utf8_get_char_validated (current, 8);
3600                 /* Invalid unichar, stop */
3601                 if (c == -1)
3602                         break;
3603                 /* a bullet */
3604                 if (c == 0x2022)
3605                         continue;
3606                 result = g_string_append_unichar (result, c);
3607                 result_len++;
3608         }
3609
3610         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3611                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3612                 if (result_len > 0)
3613                 {
3614                         /* Prevent endless recursion */
3615                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3616                         g_signal_emit_by_name (editable, "insert-text", 
3617                                                (gpointer) result->str, (gpointer) result->len,
3618                                                (gpointer) position, (gpointer) window);
3619                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3620                 }
3621         }
3622
3623         if (result_len + old_length > 1000) {
3624                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3625                                                 _CS("ckdg_ib_maximum_characters_reached"));
3626         }
3627         g_string_free (result, TRUE);
3628 }
3629
3630 void
3631 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3632                                             gboolean show)
3633 {
3634         ModestMsgEditWindowPrivate *priv = NULL;
3635
3636         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3637         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3638
3639         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3640
3641         if (show) {
3642                 gtk_widget_show_all (priv->find_toolbar);
3643                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3644         } else {
3645                 gtk_widget_hide_all (priv->find_toolbar);
3646                 gtk_widget_grab_focus (priv->msg_body);
3647         }
3648 }
3649
3650 static gboolean 
3651 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3652                                           const gchar *str,
3653                                           GtkTextIter *match_start,
3654                                           GtkTextIter *match_end)
3655 {
3656         GtkTextIter end_iter;
3657         gchar *str_casefold;
3658         gint str_chars_n;
3659         gchar *range_text;
3660         gchar *range_casefold;
3661         gint offset;
3662         gint range_chars_n;
3663         gboolean result = FALSE;
3664
3665         if (str == NULL)
3666                 return TRUE;
3667         
3668         /* get end iter */
3669         end_iter = *iter;
3670         gtk_text_iter_forward_to_end (&end_iter);
3671
3672         str_casefold = g_utf8_casefold (str, -1);
3673         str_chars_n = strlen (str);
3674
3675         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3676         range_casefold = g_utf8_casefold (range_text, -1);
3677         range_chars_n = strlen (range_casefold);
3678
3679         if (range_chars_n < str_chars_n) {
3680                 g_free (str_casefold);
3681                 g_free (range_text);
3682                 g_free (range_casefold);
3683                 return FALSE;
3684         }
3685
3686         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3687                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3688                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3689                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3690                         result = TRUE;
3691                         if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3692                                                            match_start, match_end, NULL)) {
3693                                 g_warning ("Matched string with collate, but not matched in model");
3694                         }
3695                         g_free (found_text);
3696                 }
3697                 g_free (range_subtext);
3698                 if (result)
3699                         break;
3700         }
3701         g_free (str_casefold);
3702         g_free (range_text);
3703         g_free (range_casefold);
3704
3705         return result;
3706 }
3707
3708
3709 static void 
3710 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3711                                             ModestMsgEditWindow *window)
3712 {
3713         gchar *current_search = NULL;
3714         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3715         gboolean result;
3716         GtkTextIter selection_start, selection_end;
3717         GtkTextIter match_start, match_end;
3718         gboolean continue_search = FALSE;
3719
3720         if (message_is_empty (window)) {
3721                 g_free (priv->last_search);
3722                 priv->last_search = NULL;
3723                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3724                 return;
3725         }
3726
3727         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3728         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3729                 g_free (current_search);
3730                 g_free (priv->last_search);
3731                 priv->last_search = NULL;
3732                 /* Information banner about empty search */
3733                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3734                 return;
3735         }
3736
3737         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3738                 continue_search = TRUE;
3739         } else {
3740                 g_free (priv->last_search);
3741                 priv->last_search = g_strdup (current_search);
3742         }
3743
3744         if (continue_search) {
3745                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3746                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3747                                                                    &match_start, &match_end);
3748                 if (!result)
3749                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3750         } else {
3751                 GtkTextIter buffer_start;
3752                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3753                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3754                                                                    &match_start, &match_end);
3755                 if (!result)
3756                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3757         }
3758
3759         /* Mark as selected the string found in search */
3760         if (result) {
3761                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3762                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3763                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3764         } else {
3765                 g_free (priv->last_search);
3766                 priv->last_search = NULL;
3767         }
3768         g_free (current_search);
3769 }
3770
3771 gboolean 
3772 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3773 {
3774         ModestMsgEditWindowPrivate *priv;
3775
3776         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3777         return priv->sent;
3778 }
3779
3780 void 
3781 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3782                                  gboolean sent)
3783 {
3784         ModestMsgEditWindowPrivate *priv;
3785
3786         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3787         priv->sent = sent;
3788 }
3789
3790 static void
3791 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3792                                           ModestMsgEditWindow *window)
3793 {
3794         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3795 }
3796
3797 void
3798 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3799                                   TnyMsg *draft)
3800 {
3801         ModestMsgEditWindowPrivate *priv;
3802         TnyHeader *header = NULL;
3803
3804         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3805         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3806
3807         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3808
3809         if (priv->draft_msg != NULL) {
3810                 g_object_unref (priv->draft_msg);
3811         }
3812
3813         if (draft != NULL) {
3814                 g_object_ref (draft);
3815                 header = tny_msg_get_header (draft);
3816                 if (priv->msg_uid) {
3817                         g_free (priv->msg_uid);
3818                         priv->msg_uid = NULL;
3819                 }
3820                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3821         }
3822
3823         priv->draft_msg = draft;
3824 }
3825
3826 static void  
3827 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3828                        GtkTextIter *start, GtkTextIter *end,
3829                        gpointer userdata)
3830 {
3831         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3832         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3833         gchar *tag_name;
3834
3835         if (tag == NULL) return;
3836         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3837         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3838                 replace_with_images (window, priv->images);
3839         }
3840 }
3841
3842 void                    
3843 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3844                                  TnyMimePart *part)
3845 {
3846         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3847
3848         g_return_if_fail (TNY_IS_MIME_PART (part));
3849         tny_list_prepend (priv->attachments, (GObject *) part);
3850         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3851         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3852         gtk_widget_show_all (priv->attachments_caption);
3853         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3854 }
3855
3856 const gchar*    
3857 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3858 {
3859         ModestMsgEditWindowPrivate *priv;
3860
3861         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3862         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3863
3864         return priv->msg_uid;
3865 }
3866
3867 GtkWidget *
3868 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3869                                          ModestMsgEditWindowWidgetType widget_type)
3870 {
3871         ModestMsgEditWindowPrivate *priv;
3872
3873         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3874         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3875
3876         switch (widget_type) {
3877         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3878                 return priv->msg_body;
3879                 break;
3880         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3881                 return priv->to_field;
3882                 break;
3883         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3884                 return priv->cc_field;
3885                 break;
3886         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3887                 return priv->bcc_field;
3888                 break;
3889         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3890                 return priv->subject_field;
3891                 break;
3892         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3893                 return priv->attachments_view;
3894                 break;
3895         default:
3896                 return NULL;
3897         }
3898 }
3899
3900 static void 
3901 remove_tags (WPTextBuffer *buffer)
3902 {
3903         GtkTextIter start, end;
3904
3905         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3906         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3907
3908         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3909 }
3910
3911 static void
3912 on_account_removed (TnyAccountStore *account_store, 
3913                     TnyAccount *account,
3914                     gpointer user_data)
3915 {
3916         /* Do nothing if it's a store account, because we use the
3917            transport to send the messages */
3918         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3919                 const gchar *parent_acc = NULL;
3920                 const gchar *our_acc = NULL;
3921
3922                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3923                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3924                 /* Close this window if I'm showing a message of the removed account */
3925                 if (strcmp (parent_acc, our_acc) == 0)
3926                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3927         }
3928 }
3929
3930 static void update_signature (ModestMsgEditWindow *self,
3931                               const gchar *old_account, 
3932                               const gchar *new_account)
3933 {
3934         ModestMsgEditWindowPrivate *priv;
3935         gboolean has_old_signature, has_new_signature;
3936         GtkTextIter iter;
3937         GtkTextIter match_start, match_end;
3938         ModestAccountMgr *mgr;
3939         gchar *signature;
3940         gchar *full_signature;
3941
3942         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3943
3944         gtk_text_buffer_begin_user_action (priv->text_buffer);
3945
3946         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3947         mgr = modest_runtime_get_account_mgr ();
3948
3949
3950         if (old_account) {
3951                 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
3952                 if (has_old_signature) {
3953                         full_signature = g_strconcat ("\n--\n", signature, NULL);
3954                         if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3955                                 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3956                                 iter = match_start;
3957                         } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3958                                                                  &match_start, &match_end, NULL)) {
3959                                 iter = match_start;
3960                         }
3961                         g_free (full_signature);
3962                 }
3963                 g_free (signature);
3964         }
3965
3966         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3967         signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
3968         if (has_new_signature) {
3969                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3970                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3971                 g_free (full_signature);
3972         }
3973         g_free (signature);
3974         gtk_text_buffer_end_user_action (priv->text_buffer);
3975 }
3976
3977 static void
3978 from_field_changed (HildonPickerButton *button,
3979                     ModestMsgEditWindow *self)
3980 {
3981         ModestMsgEditWindowPrivate *priv;
3982         gchar *old_account, *new_account;
3983
3984         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3985
3986         old_account = priv->last_from_account;
3987         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3988         new_account = priv->last_from_account;
3989
3990         update_signature (self, old_account, new_account);
3991
3992 }
3993
3994 typedef struct _MessageSettingsHelper {
3995         ModestMsgEditWindow *window;
3996         GSList *priority_group;
3997         GSList *format_group;
3998         GtkToggleButton *current_priority;
3999         GtkToggleButton *current_format;
4000 } MessageSettingsHelper;
4001
4002 static void
4003 on_priority_toggle (GtkToggleButton *button, 
4004                     MessageSettingsHelper *helper)
4005 {
4006         GSList *node;
4007         ModestMsgEditWindowPrivate *priv;
4008
4009         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4010         if (gtk_toggle_button_get_active (button)) {
4011
4012                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4013                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4014                         if ((node_button != button) &&
4015                             gtk_toggle_button_get_active (node_button)) {
4016                                 gtk_toggle_button_set_active (node_button, FALSE);
4017                         }
4018                 }
4019                 helper->current_priority = button;
4020         } else {
4021                 gboolean found = FALSE;
4022                 /* If no one is active, activate it again */
4023                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4024                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4025                         if (gtk_toggle_button_get_active (node_button)) {
4026                                 found = TRUE;
4027                                 break;
4028                         }
4029                 }
4030                 if (!found) {
4031                         gtk_toggle_button_set_active (button, TRUE);
4032                 }
4033         }
4034 }
4035
4036 static void
4037 on_format_toggle (GtkToggleButton *button,
4038                   MessageSettingsHelper *helper)
4039 {
4040         GSList *node;
4041         ModestMsgEditWindowPrivate *priv;
4042
4043         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4044         if (gtk_toggle_button_get_active (button)) {
4045
4046                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4047                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4048                         if ((node_button != button) &&
4049                             gtk_toggle_button_get_active (node_button)) {
4050                                 gtk_toggle_button_set_active (node_button, FALSE);
4051                         }
4052                 }
4053                 helper->current_format = button;
4054         } else {
4055                 gboolean found = FALSE;
4056                 /* If no one is active, activate it again */
4057                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4058                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4059                         if (gtk_toggle_button_get_active (node_button)) {
4060                                 found = TRUE;
4061                                 break;
4062                         }
4063                 }
4064                 if (!found) {
4065                         gtk_toggle_button_set_active (button, TRUE);
4066                 }
4067         }
4068
4069 }
4070
4071 static void
4072 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4073 {
4074         GtkWidget *dialog;
4075         GtkWidget *align;
4076         GtkWidget *vbox;
4077         GtkWidget *priority_hbox;
4078         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4079         GtkWidget *captioned;
4080         GtkSizeGroup *title_sizegroup, *value_sizegroup;
4081         GtkWidget *format_hbox;
4082         GtkWidget *html_toggle, *text_toggle;
4083         ModestMsgEditWindowPrivate *priv;
4084         MessageSettingsHelper helper = {0,};
4085
4086         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4087         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4088         helper.window = window;
4089         helper.priority_group = NULL;
4090         helper.format_group = NULL;
4091
4092         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4093         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4094
4095         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4096                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4097                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4098         vbox = gtk_vbox_new (FALSE, 0);
4099         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4100         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4101         gtk_container_add (GTK_CONTAINER (align), vbox);
4102         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4103         gtk_widget_show (align);
4104         gtk_widget_show (vbox);
4105
4106         /* Priority toggles */
4107         priority_hbox = gtk_hbox_new (TRUE, 0);
4108         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4109         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4110         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4111         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4112         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4113         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4114         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4115         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4116         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4117         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4118         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4119         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4120         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4121         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4122         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4123         gtk_widget_show_all (priority_hbox);
4124         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4125                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4126         gtk_widget_show (captioned);
4127         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4128
4129         /* format toggles */
4130         format_hbox = gtk_hbox_new (TRUE, 0);
4131         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4132         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4133         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4134         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4135         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4136         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4137         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4138         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4139         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4140         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4141         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4142         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4143         gtk_widget_show_all (format_hbox);
4144         gtk_widget_show (format_hbox);
4145         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4146
4147
4148         g_object_unref (title_sizegroup);
4149         g_object_unref (value_sizegroup);
4150
4151         /* Set current values */
4152         switch (priv->priority_flags) {
4153         case TNY_HEADER_FLAG_HIGH_PRIORITY:
4154                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4155                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4156                 break;
4157         case TNY_HEADER_FLAG_LOW_PRIORITY:
4158                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4159                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4160                 break;
4161         default:
4162                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4163                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4164                 break;
4165         }
4166
4167         switch (modest_msg_edit_window_get_format (window)) {
4168         case MODEST_MSG_EDIT_FORMAT_TEXT:
4169                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4170                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4171                 break;
4172         case MODEST_MSG_EDIT_FORMAT_HTML:
4173         default:
4174                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4175                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4176                 break;
4177         }
4178
4179         /* Signal connects */
4180         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4181         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4182         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4183         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4184         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4185
4186         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4187                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
4188
4189         /* Save settings if the user clicked on done */
4190         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4191                 TnyHeaderFlags flags;
4192                 ModestMsgEditFormat old_format, new_format;
4193
4194                 /* Set priority flags */
4195                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4196                 if (priv->priority_flags !=  flags)
4197                         modest_msg_edit_window_set_priority_flags (window, flags);
4198
4199                 /* Set edit format */
4200                 old_format = modest_msg_edit_window_get_format (window);
4201                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4202                 if (old_format != new_format) {
4203                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4204                         modest_msg_edit_window_set_file_format (window, file_format);
4205                 }
4206         }
4207
4208         gtk_widget_destroy (dialog);
4209         g_slist_free (helper.priority_group);
4210 }
4211
4212 static void
4213 on_message_settings (GtkAction *action,
4214                      ModestMsgEditWindow *window)
4215 {
4216         modest_msg_edit_window_show_msg_settings_dialog (window);
4217 }
4218
4219 static void
4220 on_cc_button_toggled (HildonCheckButton *button,
4221                       ModestMsgEditWindow *window)
4222 {
4223         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4224
4225         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4226                                         hildon_check_button_get_active (button));
4227 }
4228
4229 static void
4230 on_bcc_button_toggled (HildonCheckButton *button,
4231                       ModestMsgEditWindow *window)
4232 {
4233         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4234
4235         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4236                                         hildon_check_button_get_active (button));
4237 }
4238
4239 static void 
4240 setup_menu (ModestMsgEditWindow *self)
4241 {
4242         ModestMsgEditWindowPrivate *priv = NULL;
4243
4244         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4245
4246         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4247
4248         /* Settings menu buttons */
4249         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4250                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4251                                            NULL);
4252         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4253                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4254                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4255
4256         priv->cc_button = hildon_check_button_new (0);
4257         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4258         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4259                                         FALSE);
4260         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4261                                                   NULL);
4262         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4263                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4264         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4265         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4266
4267         priv->bcc_button = hildon_check_button_new (0);
4268         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4269         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4270                                         FALSE);
4271         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4272                                                   NULL);
4273         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4274                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4275         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4276         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4277
4278         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4279                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4280                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4281         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("TODO: add attachment"), NULL,
4282                                            APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4283                                            NULL);
4284         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4285                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4286                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4287         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4288                                            APP_MENU_CALLBACK (on_message_settings),
4289                                            NULL);
4290         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4291                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4292                                            NULL);
4293 }
4294
4295 static void
4296 emit_open_addressbook (GtkButton *button,
4297                        ModestRecptEditor *editor)
4298 {
4299         g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4300 }
4301
4302 static GtkWidget *
4303 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4304                          const gchar *label, GtkWidget *control)
4305 {
4306         GtkWidget *abook_button;
4307         GtkWidget *align;
4308         GtkWidget *box;
4309         GtkWidget *label_widget;
4310
4311         box = gtk_hbox_new (FALSE, 0);
4312
4313         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4314         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4315
4316         abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4317         label_widget = gtk_label_new (label);
4318         gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4319         gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4320
4321         gtk_container_add (GTK_CONTAINER (align), abook_button);
4322         gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4323         gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4324         gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4325         if (title_size_group)
4326                 gtk_size_group_add_widget (title_size_group, label_widget);
4327         if (value_size_group)
4328                 gtk_size_group_add_widget (value_size_group, control);
4329
4330         g_signal_connect (G_OBJECT (abook_button), "clicked",
4331                           G_CALLBACK (emit_open_addressbook), control);
4332   
4333         return box;  
4334 }