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