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