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