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