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