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