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