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