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