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