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