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