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