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