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