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