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