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