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