* src/maemo/modest-msg-edit-window.c:
[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         /* Get the default format required from configuration */
1223         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1224                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1225         }
1226
1227         /* Set the default focus depending on having already a To: field or not */
1228         if ((!to)||(*to == '\0')) {
1229                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1230         } else {
1231                 gtk_widget_grab_focus (priv->msg_body);
1232         }
1233
1234         /* TODO: lower priority, select in the From: combo to the
1235            value that comes from msg <- not sure, should it be
1236            allowed? */
1237         
1238         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1239
1240         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1241         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1242
1243         modest_msg_edit_window_set_modified (self, FALSE);
1244
1245         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1246         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1247         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1248         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1249
1250         if (priv->msg_uid) {
1251                 g_free (priv->msg_uid);
1252                 priv->msg_uid = NULL;
1253         }
1254
1255         /* we should set a reference to the incoming message if it is a draft */
1256         msg_folder = tny_msg_get_folder (msg);
1257         if (msg_folder) {               
1258                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1259                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1260                         if (type == TNY_FOLDER_TYPE_INVALID)
1261                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1262                         
1263                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1264                                 priv->draft_msg = g_object_ref(msg);
1265                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1266                                 priv->outbox_msg = g_object_ref(msg);
1267                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1268                 }
1269                 g_object_unref (msg_folder);
1270         }
1271
1272         g_free (to);
1273         g_free (subject);
1274         g_free (cc);
1275         g_free (bcc);
1276 }
1277
1278 static void
1279 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1280                                 gpointer data)
1281 {
1282         GList *item_children, *node;
1283         GtkWidget *bin_child;
1284
1285         bin_child = gtk_bin_get_child (GTK_BIN(item));
1286
1287         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1288         
1289         for (node = item_children; node != NULL; node = g_list_next (node)) {
1290                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1291                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1292                 }
1293         }
1294         g_list_free (item_children);
1295 }
1296
1297 static void
1298 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1299 {
1300         GtkWidget *box;
1301         GList *item_children, *node;
1302
1303         box = gtk_bin_get_child (GTK_BIN (item));
1304         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1305         item_children = gtk_container_get_children (GTK_CONTAINER (box));
1306         
1307         for (node = item_children; node != NULL; node = g_list_next (node)) {
1308                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1309                 if (GTK_IS_TOGGLE_BUTTON (node->data))
1310                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1311                 else if (GTK_IS_BUTTON (node->data))
1312                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1313         }
1314         g_list_free (item_children);
1315 }
1316
1317
1318 static void
1319 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1320 {
1321         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1322         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1323         GtkWidget *placeholder;
1324         GtkWidget *tool_item;
1325         gint insert_index;
1326         gchar size_text[5];
1327         gint size_index;
1328         gint font_index;
1329         GtkWidget *sizes_menu;
1330         GtkWidget *fonts_menu;
1331         GSList *radio_group = NULL;
1332         GSList *node = NULL;
1333         gchar *markup;
1334
1335         /* Toolbar */
1336         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1337         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1338
1339         /* Font color placeholder */
1340         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1341         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1342
1343         /* font color */
1344         tool_item = GTK_WIDGET (gtk_tool_item_new ());
1345         priv->font_color_button = hildon_color_button_new ();
1346         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1347         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1348         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
1349         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1350         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1351         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1352         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1353                                   "notify::color", 
1354                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1355                                   window);
1356
1357         /* Font size and face placeholder */
1358         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1359         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1360         /* font_size */
1361         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1362         priv->size_tool_button_label = gtk_label_new (NULL);
1363         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1364         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1365                               size_text,"</span>", NULL);
1366         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1367         g_free (markup);
1368         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1369         sizes_menu = gtk_menu_new ();
1370         priv->size_items_group = NULL;
1371         radio_group = NULL;
1372         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1373                 GtkWidget *size_menu_item;
1374
1375                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1376                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1377                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1378                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1379                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1380                 gtk_widget_show (size_menu_item);
1381
1382                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1383                         
1384         }
1385
1386         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1387                 GtkWidget *item = (GtkWidget *) node->data;
1388                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1389                                   window);
1390         }
1391
1392         priv->size_items_group = g_slist_reverse (priv->size_items_group);
1393         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1394         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1395         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1396         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1397         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1398         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1399         priv->font_size_toolitem = tool_item;
1400
1401         /* font face */
1402         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1403         priv->font_tool_button_label = gtk_label_new (NULL);
1404         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1405         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1406         g_free(markup);
1407         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1408         fonts_menu = gtk_menu_new ();
1409         priv->font_items_group = NULL;
1410         radio_group = NULL;
1411         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1412                 GtkWidget *font_menu_item;
1413                 GtkWidget *child_label;
1414
1415                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1416                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1417                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
1418                                       wp_get_font_name (font_index), "</span>", NULL);
1419                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1420                 g_free (markup);
1421                 
1422                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1423                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1424                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1425                 gtk_widget_show (font_menu_item);
1426
1427                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1428                         
1429         }
1430         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1431                 GtkWidget *item = (GtkWidget *) node->data;
1432                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1433                                   window);
1434         }
1435         priv->font_items_group = g_slist_reverse (priv->font_items_group);
1436         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1437         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1438         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1439         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1440         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1441         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1442         priv->font_face_toolitem = tool_item;
1443
1444         /* Set expand and homogeneous for remaining items */
1445         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1446         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1447         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1448         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1449         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1450         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1451         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1452         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1453         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1454
1455         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1456            will not show the tool items added to the placeholders) */
1457         gtk_widget_show_all (parent_priv->toolbar);
1458
1459         /* Set the no show all *after* showing all items. We do not
1460            want the toolbar to be shown with a show all because it
1461            could go agains the gconf setting regarding showing or not
1462            the toolbar of the editor window */
1463         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1464 }
1465
1466
1467
1468 ModestWindow*
1469 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1470 {
1471         GObject *obj;
1472         ModestWindowPrivate *parent_priv;
1473         ModestMsgEditWindowPrivate *priv;
1474         ModestDimmingRulesGroup *menu_rules_group = NULL;
1475         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1476         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1477         ModestWindowMgr *mgr = NULL;
1478
1479         g_return_val_if_fail (msg, NULL);
1480         g_return_val_if_fail (account_name, NULL);
1481
1482         mgr = modest_runtime_get_window_mgr ();
1483         
1484         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1485
1486         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1487         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1488
1489         /* Menubar. Update the state of some toggles */
1490         parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1491         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1492         priv->from_field_protos = get_transports ();
1493         modest_combo_box_set_pair_list (MODEST_COMBO_BOX (priv->from_field), priv->from_field_protos);
1494         modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), (gpointer) account_name);
1495         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1496         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1497
1498         /* Init window */
1499         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1500
1501         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1502                 
1503         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1504
1505         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1506
1507         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1508         menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1509         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1510         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1511         /* Add common dimming rules */
1512         modest_dimming_rules_group_add_rules (menu_rules_group, 
1513                                               modest_msg_edit_window_menu_dimming_entries,
1514                                               G_N_ELEMENTS (modest_msg_edit_window_menu_dimming_entries),
1515                                               MODEST_WINDOW (obj));
1516         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1517                                               modest_msg_edit_window_toolbar_dimming_entries,
1518                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1519                                               MODEST_WINDOW (obj));
1520         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_button,
1521                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1522                                                     MODEST_WINDOW (obj));
1523         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1524                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1525                                                     MODEST_WINDOW (obj));
1526         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1527                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1528                                                     MODEST_WINDOW (obj));
1529         modest_dimming_rules_group_add_rules (clipboard_rules_group, 
1530                                               modest_msg_edit_window_clipboard_dimming_entries,
1531                                               G_N_ELEMENTS (modest_msg_edit_window_clipboard_dimming_entries),
1532                                               MODEST_WINDOW (obj));
1533         /* Insert dimming rules group for this window */
1534         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1535         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1536         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1537         /* Checks the dimming rules */
1538         g_object_unref (menu_rules_group);
1539         g_object_unref (toolbar_rules_group);
1540         g_object_unref (clipboard_rules_group);
1541         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1542
1543         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1544
1545         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1546         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1547         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1548         priv->update_caption_visibility = TRUE;
1549
1550         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1551
1552         /* Track account-removed signal, this window should be closed
1553            in the case we're creating a mail associated to the account
1554            that is deleted */
1555         priv->account_removed_handler_id = 
1556                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1557                                   "account_removed",
1558                                   G_CALLBACK(on_account_removed),
1559                                   obj);
1560
1561         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1562
1563         return (ModestWindow*) obj;
1564 }
1565
1566 static gint
1567 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1568 {
1569         GString **string_buffer = (GString **) user_data;
1570
1571         *string_buffer = g_string_append (*string_buffer, buffer);
1572    
1573         return 0;
1574 }
1575
1576 /**
1577  * @result: A new string which should be freed with g_free().
1578  */
1579 static gchar *
1580 get_formatted_data (ModestMsgEditWindow *edit_window)
1581 {
1582         ModestMsgEditWindowPrivate *priv;
1583         GString *string_buffer = g_string_new ("");
1584         
1585         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1586
1587         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1588
1589         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1590
1591         return g_string_free (string_buffer, FALSE);
1592                                                                         
1593 }
1594
1595 MsgData * 
1596 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1597 {
1598         MsgData *data;
1599         const gchar *account_name;
1600         ModestMsgEditWindowPrivate *priv;
1601         TnyIterator *att_iter;
1602         
1603         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1604
1605         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1606                                                                         
1607         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1608         g_return_val_if_fail (account_name, NULL);
1609         
1610         
1611         /* don't free these (except from) */
1612         data = g_slice_new0 (MsgData);
1613         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1614                                                              account_name);
1615         data->account_name = g_strdup (account_name);
1616         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1617         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1618         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1619         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1620         if (priv->draft_msg) {
1621                 data->draft_msg = g_object_ref (priv->draft_msg);
1622         } else if (priv->outbox_msg) {
1623                 data->draft_msg = g_object_ref (priv->outbox_msg);
1624         } else {
1625                 data->draft_msg = NULL;
1626         }
1627
1628         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1629         GtkTextIter b, e;
1630         gtk_text_buffer_get_bounds (buf, &b, &e);
1631         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1632
1633         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1634                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1635         else
1636                 data->html_body = NULL;
1637
1638         /* deep-copy the data */
1639         att_iter = tny_list_create_iterator (priv->attachments);
1640         data->attachments = NULL;
1641         while (!tny_iterator_is_done (att_iter)) {
1642                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1643                 if (!(TNY_IS_MIME_PART(part))) {
1644                         g_warning ("strange data in attachment list");
1645                         g_object_unref (part);
1646                         tny_iterator_next (att_iter);
1647                         continue;
1648                 }
1649                 data->attachments = g_list_append (data->attachments,
1650                                                    part);
1651                 tny_iterator_next (att_iter);
1652         }
1653         g_object_unref (att_iter);
1654
1655         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1656         att_iter = tny_list_create_iterator (priv->images);
1657         data->images = NULL;
1658         while (!tny_iterator_is_done (att_iter)) {
1659                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1660                 const gchar *cid;
1661                 if (!(TNY_IS_MIME_PART(part))) {
1662                         g_warning ("strange data in attachment list");
1663                         g_object_unref (part);
1664                         tny_iterator_next (att_iter);
1665                         continue;
1666                 }
1667                 cid = tny_mime_part_get_content_id (part);
1668                 if (cid) {                      
1669                         gchar *image_tag_id;
1670                         GtkTextTag *image_tag;
1671                         GtkTextIter iter;
1672                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1673                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1674                         g_free (image_tag_id);
1675                         
1676                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1677                         if (image_tag && 
1678                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1679                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1680                                 data->images = g_list_append (data->images,
1681                                                               g_object_ref (part));
1682                 }
1683                 g_object_unref (part);
1684                 tny_iterator_next (att_iter);
1685         }
1686         g_object_unref (att_iter);
1687         
1688         data->priority_flags = priv->priority_flags;
1689
1690         return data;
1691 }
1692
1693
1694 static void
1695 unref_gobject (GObject *obj, gpointer data)
1696 {
1697         if (!G_IS_OBJECT(obj))
1698                 return;
1699         g_object_unref (obj);
1700 }
1701
1702 void 
1703 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1704                                                       MsgData *data)
1705 {
1706         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1707
1708         if (!data)
1709                 return;
1710
1711         g_free (data->to);
1712         g_free (data->cc);
1713         g_free (data->bcc);
1714         g_free (data->from);
1715         g_free (data->subject);
1716         g_free (data->plain_body);
1717         g_free (data->html_body);
1718         g_free (data->account_name);
1719         
1720         if (data->draft_msg != NULL) {
1721                 g_object_unref (data->draft_msg);
1722                 data->draft_msg = NULL;
1723         }
1724         
1725         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1726         g_list_free (data->attachments);
1727         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1728         g_list_free (data->images);
1729         
1730         g_slice_free (MsgData, data);
1731 }
1732
1733 void                    
1734 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1735                                        gint *parts_count,
1736                                        guint64 *parts_size)
1737 {
1738         ModestMsgEditWindowPrivate *priv;
1739
1740         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1741
1742         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1743
1744         /* TODO: add images */
1745         *parts_size += priv->images_size;
1746         *parts_count += priv->images_count;
1747
1748 }
1749
1750 ModestMsgEditFormat
1751 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1752 {
1753         gboolean rich_text;
1754         ModestMsgEditWindowPrivate *priv = NULL;
1755         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1756
1757         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1758
1759         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1760         if (rich_text)
1761                 return MODEST_MSG_EDIT_FORMAT_HTML;
1762         else
1763                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1764 }
1765
1766 void
1767 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1768                                    ModestMsgEditFormat format)
1769 {
1770         ModestMsgEditWindowPrivate *priv;
1771
1772         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1773         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1774
1775         switch (format) {
1776         case MODEST_MSG_EDIT_FORMAT_HTML:
1777                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1778                 break;
1779         case MODEST_MSG_EDIT_FORMAT_TEXT:
1780                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1781                 break;
1782         default:
1783                 g_return_if_reached ();
1784         }
1785 }
1786
1787 ModestMsgEditFormatState *
1788 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1789 {
1790         ModestMsgEditFormatState *format_state = NULL;
1791         ModestMsgEditWindowPrivate *priv;
1792         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1793
1794         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1795         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1796
1797         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1798
1799         format_state = g_new0 (ModestMsgEditFormatState, 1);
1800         format_state->bold = buffer_format->bold&0x1;
1801         format_state->italics = buffer_format->italic&0x1;
1802         format_state->bullet = buffer_format->bullet&0x1;
1803         format_state->color = buffer_format->color;
1804         format_state->font_size = buffer_format->font_size;
1805         format_state->font_family = wp_get_font_name (buffer_format->font);
1806         format_state->justification = buffer_format->justification;
1807         g_free (buffer_format);
1808
1809         return format_state;
1810  
1811 }
1812
1813 void
1814 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1815                                          const ModestMsgEditFormatState *format_state)
1816 {
1817         ModestMsgEditWindowPrivate *priv;
1818         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1819         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1820         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1821         g_return_if_fail (format_state != NULL);
1822
1823         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1824         gtk_widget_grab_focus (priv->msg_body);
1825         buffer_format->bold = (format_state->bold != FALSE);
1826         buffer_format->italic = (format_state->italics != FALSE);
1827         buffer_format->color = format_state->color;
1828         buffer_format->font_size = format_state->font_size;
1829         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1830         buffer_format->justification = format_state->justification;
1831         buffer_format->bullet = format_state->bullet;
1832
1833         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1834
1835         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1836         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1837         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1838         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1839         buffer_format->cs.font = (buffer_format->font != current_format->font);
1840         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1841         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1842
1843         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1844         if (buffer_format->cs.bold) {
1845                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1846                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1847         }
1848         if (buffer_format->cs.italic) {
1849                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1850                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1851         }
1852         if (buffer_format->cs.color) {
1853                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1854                                               GINT_TO_POINTER (&(buffer_format->color)));
1855         }
1856         if (buffer_format->cs.font_size) {
1857                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1858                                               GINT_TO_POINTER (buffer_format->font_size));
1859         }
1860         if (buffer_format->cs.justification) {
1861                 switch (buffer_format->justification) {
1862                 case GTK_JUSTIFY_LEFT:
1863                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1864                                                       GINT_TO_POINTER(TRUE));
1865                         break;
1866                 case GTK_JUSTIFY_CENTER:
1867                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1868                                                       GINT_TO_POINTER(TRUE));
1869                         break;
1870                 case GTK_JUSTIFY_RIGHT:
1871                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1872                                                       GINT_TO_POINTER(TRUE));
1873                         break;
1874                 default:
1875                         break;
1876                 }
1877                         
1878         }
1879         if (buffer_format->cs.font) {
1880                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1881                                               GINT_TO_POINTER (buffer_format->font));
1882         }
1883         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1884         if (buffer_format->cs.bullet) {
1885                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1886                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1887         }
1888 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1889         
1890         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1891         
1892         g_free (current_format);
1893
1894 }
1895
1896 static void
1897 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1898 {
1899         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1900         GtkAction *action;
1901         ModestWindowPrivate *parent_priv;
1902         ModestMsgEditWindowPrivate *priv;
1903         GtkWidget *new_size_menuitem;
1904         GtkWidget *new_font_menuitem;
1905         
1906         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1907         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1908
1909         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1910                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1911                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1912                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1913         } else {
1914                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1915                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1916                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1917         }
1918
1919         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1920
1921         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1922         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1923
1924         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1925         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1926
1927 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1928 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1929
1930         action = NULL;
1931         switch (buffer_format->justification)
1932         {
1933         case GTK_JUSTIFY_LEFT:
1934                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1935                 break;
1936         case GTK_JUSTIFY_CENTER:
1937                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1938                 break;
1939         case GTK_JUSTIFY_RIGHT:
1940                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1941                 break;
1942         default:
1943                 break;
1944         }
1945         
1946         if (action != NULL)
1947                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1948         
1949         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1950                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1951                                          window);
1952         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1953         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1954                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1955                                            window);
1956
1957         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1958                                                       buffer_format->font_size))->data);
1959         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1960                 GtkWidget *label;
1961                 gchar *markup;
1962
1963                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1964                 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1965                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1966                 g_free (markup);
1967                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1968                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1969                                                  window);
1970                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1971                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1972                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1973                                                    window);
1974         }
1975
1976         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1977                                                       buffer_format->font))->data);
1978         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1979                 GtkWidget *label;
1980                 gchar *markup;
1981
1982                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1983                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1984                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1985                 g_free (markup);
1986                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1987                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1988                                                  window);
1989                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1990                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1991                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1992                                                    window);
1993         }
1994
1995         g_free (buffer_format);
1996
1997 }
1998
1999 #ifdef MODEST_HILDON_VERSION_0
2000 void
2001 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2002 {
2003         
2004         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2005         ModestMsgEditWindowPrivate *priv;
2006         GtkWidget *dialog = NULL;
2007         gint response;
2008         GdkColor *new_color = NULL;
2009
2010         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2011         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2012         
2013         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2014         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2015         g_free (buffer_format);
2016
2017         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2018                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2019                 if (new_color != NULL) {
2020                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2021                                                       (gpointer) new_color);
2022                 }
2023         }
2024         gtk_widget_destroy (dialog);
2025 }
2026
2027
2028 void
2029 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2030 {
2031         
2032         ModestMsgEditWindowPrivate *priv;
2033         GtkWidget *dialog = NULL;
2034         gint response;
2035         GdkColor *old_color = NULL;
2036         const GdkColor *new_color = NULL;
2037         
2038         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2039         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2040         
2041         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2042         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2043
2044         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2045                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2046                 if (new_color != NULL)
2047                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2048         }
2049         gtk_widget_destroy (dialog);
2050
2051 }
2052
2053 #else 
2054 void
2055 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2056 {
2057         
2058         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2059         ModestMsgEditWindowPrivate *priv;
2060         GtkWidget *dialog = NULL;
2061
2062         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2063         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2064                 
2065         dialog = hildon_color_chooser_new ();
2066         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2067         g_free (buffer_format);
2068
2069         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2070                 GdkColor col;
2071                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2072                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2073                                               (gpointer) &col);
2074         }
2075         gtk_widget_destroy (dialog);
2076 }
2077
2078
2079 void
2080 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2081 {
2082         
2083         ModestMsgEditWindowPrivate *priv;
2084         GtkWidget *dialog = NULL;
2085         GdkColor *old_color = NULL;
2086         
2087         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2088         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2089         
2090         dialog = hildon_color_chooser_new ();
2091         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2092
2093         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2094                 GdkColor col;
2095                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2096                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2097         }
2098         gtk_widget_destroy (dialog);
2099 }
2100
2101 #endif /*!MODEST_HILDON_VERSION_0*/
2102
2103
2104
2105 static TnyStream*
2106 create_stream_for_uri (const gchar* uri)
2107 {
2108         if (!uri)
2109                 return NULL;
2110                 
2111         TnyStream *result = NULL;
2112
2113         GnomeVFSHandle *handle = NULL;
2114         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2115         if (test == GNOME_VFS_OK) {
2116                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2117                 /* Streams over OBEX (Bluetooth) are not seekable but
2118                  * we expect them to be (we might need to read them
2119                  * several times). So if this is a Bluetooth URI just
2120                  * read the whole file into memory (this is not a fast
2121                  * protocol so we can assume that these files are not
2122                  * going to be very big) */
2123                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2124                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2125                         TnyStream *memstream = tny_camel_mem_stream_new ();
2126                         tny_stream_write_to_stream (vfssstream, memstream);
2127                         g_object_unref (vfssstream);
2128                         result = memstream;
2129                 } else {
2130                         result = vfssstream;
2131                 }
2132         }
2133         
2134         return result;
2135 }
2136
2137 void
2138 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2139 {
2140         
2141         ModestMsgEditWindowPrivate *priv;
2142         GtkWidget *dialog = NULL;
2143         gint response = 0;
2144         GSList *uris = NULL;
2145         GSList *uri_node = NULL;
2146         
2147         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2148         
2149         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2150         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2151         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2152
2153         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2154
2155         response = gtk_dialog_run (GTK_DIALOG (dialog));
2156         switch (response) {
2157         case GTK_RESPONSE_OK:
2158                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2159                 break;
2160         default:
2161                 break;
2162         }
2163         gtk_widget_destroy (dialog);
2164
2165         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2166                 const gchar *uri;
2167                 GnomeVFSHandle *handle = NULL;
2168                 GnomeVFSResult result;
2169                 GtkTextIter position;
2170                 GtkTextMark *insert_mark;
2171
2172                 uri = (const gchar *) uri_node->data;
2173                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2174                 if (result == GNOME_VFS_OK) {
2175                         GdkPixbuf *pixbuf;
2176                         GnomeVFSFileInfo *info;
2177                         gchar *filename, *basename, *escaped_filename;
2178                         TnyMimePart *mime_part;
2179                         gchar *content_id;
2180                         const gchar *mime_type = NULL;
2181                         GnomeVFSURI *vfs_uri;
2182                         guint64 stream_size;
2183
2184                         gnome_vfs_close (handle);
2185                         vfs_uri = gnome_vfs_uri_new (uri);
2186
2187                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2188                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2189                         g_free (escaped_filename);
2190                         gnome_vfs_uri_unref (vfs_uri);
2191                         info = gnome_vfs_file_info_new ();
2192
2193                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2194                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2195                             == GNOME_VFS_OK)
2196                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2197
2198                         mime_part = tny_platform_factory_new_mime_part
2199                                 (modest_runtime_get_platform_factory ());
2200                                 
2201                         TnyStream *stream = create_stream_for_uri (uri);
2202
2203                         if (stream == NULL) {
2204
2205                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2206                                 
2207                                 g_object_unref (mime_part);
2208                                 gnome_vfs_file_info_unref (info);
2209                                 continue;
2210                         }
2211
2212                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2213                         
2214                         content_id = g_strdup_printf ("%d", priv->next_cid);
2215                         tny_mime_part_set_content_id (mime_part, content_id);
2216                         g_free (content_id);
2217                         priv->next_cid++;
2218                         
2219                         basename = g_path_get_basename (filename);
2220                         tny_mime_part_set_filename (mime_part, basename);
2221                         g_free (basename);
2222
2223                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2224                         
2225                         if (pixbuf != NULL) {
2226                                 priv->images_size += stream_size;
2227                                 priv->images_count ++;
2228                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2229                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2230                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2231                         } 
2232
2233                         tny_list_prepend (priv->images, (GObject *) mime_part);
2234                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2235                         g_free (filename);
2236                         g_object_unref (mime_part);
2237                         gnome_vfs_file_info_unref (info);
2238
2239                 }
2240         }
2241
2242
2243 }
2244
2245 void
2246 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2247 {       
2248         GtkWidget *dialog = NULL;
2249         gint response = 0;
2250         GSList *uris = NULL;
2251         GSList *uri_node;
2252         GnomeVFSFileSize total_size, allowed_size;
2253         ModestMsgEditWindowPrivate *priv;
2254         gint att_num;
2255         guint64 att_size;
2256
2257         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2258                 
2259         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2260
2261         if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
2262                 return;
2263         
2264         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2265         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2266         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2267         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
2268
2269         response = gtk_dialog_run (GTK_DIALOG (dialog));
2270         switch (response) {
2271         case GTK_RESPONSE_OK:
2272                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2273                 break;
2274         default:
2275                 break;
2276         }
2277         gtk_widget_destroy (dialog);
2278
2279         /* allowed size is the maximum size - what's already there */
2280         modest_attachments_view_get_sizes (
2281                 MODEST_ATTACHMENTS_VIEW (priv->attachments_view), 
2282                 &att_num, &att_size);
2283         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2284
2285         total_size = 0;
2286         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2287
2288                 const gchar *uri = (const gchar *) uri_node->data;
2289                 
2290                 total_size += modest_msg_edit_window_attach_file_one 
2291                         (window, uri, allowed_size);
2292                 
2293                 if (total_size > allowed_size) {
2294                         g_warning ("%s: total size: %u", 
2295                                    __FUNCTION__, (unsigned int)total_size);
2296                         break;
2297                 }
2298
2299                 allowed_size -= total_size;
2300                 
2301
2302         }
2303         g_slist_foreach (uris, (GFunc) g_free, NULL);
2304         g_slist_free (uris);
2305 }
2306
2307
2308 GnomeVFSFileSize
2309 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2310                                         const gchar *uri, 
2311                                         GnomeVFSFileSize allowed_size)
2312
2313 {
2314         GnomeVFSHandle *handle = NULL;
2315         ModestMsgEditWindowPrivate *priv;
2316         GnomeVFSResult result;
2317         GnomeVFSFileSize size = 0;
2318
2319         g_return_val_if_fail (window, 0);
2320         g_return_val_if_fail (uri, 0);
2321                 
2322         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2323         
2324         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2325         if (result == GNOME_VFS_OK) {
2326                 TnyMimePart *mime_part;
2327                 TnyStream *stream;
2328                 const gchar *mime_type = NULL;
2329                 gchar *basename;
2330                 gchar *escaped_filename;
2331                 gchar *filename;
2332                 gchar *content_id;
2333                 GnomeVFSFileInfo *info;
2334                 GnomeVFSURI *vfs_uri;
2335
2336                 gnome_vfs_close (handle);
2337                 vfs_uri = gnome_vfs_uri_new (uri);
2338                 
2339
2340                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2341                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2342                 g_free (escaped_filename);
2343                 gnome_vfs_uri_unref (vfs_uri);
2344
2345                 info = gnome_vfs_file_info_new ();
2346                 
2347                 if (gnome_vfs_get_file_info (uri, 
2348                                              info, 
2349                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2350                     == GNOME_VFS_OK)
2351                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2352                 mime_part = tny_platform_factory_new_mime_part
2353                         (modest_runtime_get_platform_factory ());
2354                 
2355                 /* try to get the attachment's size; this may fail for weird
2356                  * file systems, like obex, upnp... */
2357                 if (allowed_size != 0 &&
2358                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2359                         size = info->size;
2360                         if (size > allowed_size) {
2361                                 g_warning ("%s: attachment too big", __FUNCTION__);
2362                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2363                                 return 0;
2364                         }
2365                 } else
2366                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2367                 
2368                 stream = create_stream_for_uri (uri);
2369                 
2370                 if (stream == NULL) {
2371
2372                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2373
2374                         g_object_unref (mime_part);
2375                         gnome_vfs_file_info_unref (info);
2376                         return 0;
2377                 }
2378
2379                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2380                 g_object_unref (stream);
2381                 
2382                 content_id = g_strdup_printf ("%d", priv->next_cid);
2383                 tny_mime_part_set_content_id (mime_part, content_id);
2384                 g_free (content_id);
2385                 priv->next_cid++;
2386                 
2387                 basename = g_path_get_basename (filename);
2388                 tny_mime_part_set_filename (mime_part, basename);
2389                 g_free (basename);
2390                 
2391                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2392                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2393                                                         mime_part,
2394                                                         info->size == 0, info->size);
2395                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2396                 gtk_widget_show_all (priv->attachments_caption);
2397                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2398                 g_free (filename);
2399                 g_object_unref (mime_part);
2400                 gnome_vfs_file_info_unref (info);
2401         }
2402
2403         return size;
2404 }
2405
2406 void
2407 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2408                                            TnyList *att_list)
2409 {
2410         ModestMsgEditWindowPrivate *priv;
2411         TnyIterator *iter;
2412
2413         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2414         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2415
2416         if (att_list == NULL) {
2417                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2418         } else {
2419                 g_object_ref (att_list);
2420         }
2421
2422         if (tny_list_get_length (att_list) == 0) {
2423                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2424         } else {
2425                 GtkWidget *confirmation_dialog = NULL;
2426                 gboolean dialog_response;
2427                 gchar *message = NULL;
2428                 gchar *filename = NULL;
2429
2430                 if (tny_list_get_length (att_list) == 1) {
2431                         TnyMimePart *part;
2432                         iter = tny_list_create_iterator (att_list);
2433                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2434                         g_object_unref (iter);
2435                         if (TNY_IS_MSG (part)) {
2436                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2437                                 if (header) {
2438                                         filename = tny_header_dup_subject (header);
2439                                         g_object_unref (header);
2440                                 }
2441                                 if (filename == NULL) {
2442                                         filename = g_strdup (_("mail_va_no_subject"));
2443                                 }
2444                         } else {
2445                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2446                         }
2447                         g_object_unref (part);
2448                 } else {
2449                         filename = g_strdup ("");
2450                 }
2451                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2452                                                     tny_list_get_length (att_list)), filename);
2453                 g_free (filename);
2454                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2455                 g_free (message);
2456                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2457                 gtk_widget_destroy (confirmation_dialog);
2458                 if (!dialog_response) {
2459                         g_object_unref (att_list);
2460                         return;
2461                 }
2462                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2463                 
2464                 for (iter = tny_list_create_iterator (att_list);
2465                      !tny_iterator_is_done (iter);
2466                      tny_iterator_next (iter)) {
2467                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2468                         const gchar *att_id;
2469                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2470
2471                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2472                                                                    mime_part);
2473                         if (tny_list_get_length (priv->attachments) == 0)
2474                                 gtk_widget_hide (priv->attachments_caption);
2475                         att_id = tny_mime_part_get_content_id (mime_part);
2476                         if (att_id != NULL)
2477                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2478                                                                  att_id);
2479                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2480                         g_object_unref (mime_part);
2481                 }
2482                 g_object_unref (iter);
2483         }
2484
2485         g_object_unref (att_list);
2486
2487         /* if the last attachment has been removed, focus the Subject: field */
2488         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2489                 gtk_widget_grab_focus (priv->subject_field);
2490 }
2491
2492 static void
2493 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2494                                             gpointer userdata)
2495 {
2496         ModestMsgEditWindowPrivate *priv;
2497         GdkColor *new_color;
2498         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2499         
2500 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2501         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2502 #else 
2503         GdkColor col;
2504         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2505         new_color = &col;
2506 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2507
2508         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2509         
2510         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2511
2512 }
2513
2514 static void
2515 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2516                                     gpointer userdata)
2517 {
2518         ModestMsgEditWindowPrivate *priv;
2519         gint new_size_index;
2520         ModestMsgEditWindow *window;
2521         GtkWidget *label;
2522         
2523         window = MODEST_MSG_EDIT_WINDOW (userdata);
2524         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2525         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2526
2527         if (gtk_check_menu_item_get_active (menu_item)) {
2528                 gchar *markup;
2529                 WPTextBufferFormat format;
2530
2531                 memset (&format, 0, sizeof (format));
2532                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2533
2534                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2535                 
2536                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2537                 format.cs.font_size = TRUE;
2538                 format.cs.text_position = TRUE;
2539                 format.cs.font = TRUE;
2540                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2541 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2542
2543                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2544                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2545                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2546                 
2547                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2548                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2549                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2550                 g_free (markup);
2551         }
2552 }
2553
2554 static void
2555 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2556                                     gpointer userdata)
2557 {
2558         ModestMsgEditWindowPrivate *priv;
2559         gint new_font_index;
2560         ModestMsgEditWindow *window;
2561         GtkWidget *label;
2562         
2563         window = MODEST_MSG_EDIT_WINDOW (userdata);
2564         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2565         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2566
2567         if (gtk_check_menu_item_get_active (menu_item)) {
2568                 gchar *markup;
2569
2570                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2571                 
2572                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2573
2574                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2575                                                    GINT_TO_POINTER(new_font_index)))
2576                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2577                 
2578                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2579                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2580                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2581                 g_free (markup);
2582         }
2583 }
2584
2585 static gboolean
2586 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2587 {
2588         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2589                 ModestWindowPrivate *parent_priv;
2590                 ModestWindowMgr *mgr;
2591                 gboolean is_fullscreen;
2592                 GtkAction *fs_toggle_action;
2593                 gboolean active;
2594
2595                 mgr = modest_runtime_get_window_mgr ();
2596                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2597
2598                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2599                 
2600                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2601                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2602                 if (is_fullscreen != active)
2603                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2604         }
2605
2606         return FALSE;
2607
2608 }
2609
2610 void
2611 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2612                                 gboolean show)
2613 {
2614         ModestMsgEditWindowPrivate *priv = NULL;
2615         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2616
2617         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2618         if (!priv->update_caption_visibility)
2619                 return;
2620
2621         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2622         if (show)
2623                 gtk_widget_show (priv->cc_caption);
2624         else
2625                 gtk_widget_hide (priv->cc_caption);
2626
2627         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2628 }
2629
2630 void
2631 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2632                                  gboolean show)
2633 {
2634         ModestMsgEditWindowPrivate *priv = NULL;
2635         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2636
2637         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2638         if (!priv->update_caption_visibility)
2639                 return;
2640
2641         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2642         if (show)
2643                 gtk_widget_show (priv->bcc_caption);
2644         else
2645                 gtk_widget_hide (priv->bcc_caption);
2646
2647         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2648 }
2649
2650 static void
2651 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2652                                          ModestRecptEditor *editor)
2653 {
2654         ModestMsgEditWindowPrivate *priv;
2655
2656         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2657         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2658         
2659         /* we check for low-mem; in that case, show a warning, and don't allow
2660          * for the addressbook
2661          */
2662         if (modest_platform_check_memory_low (MODEST_WINDOW(window)))
2663                 return;
2664
2665
2666         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2667
2668         if (editor == NULL) {
2669                 GtkWidget *view_focus;
2670                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2671
2672                 /* This code should be kept in sync with ModestRecptEditor. The
2673                    textview inside the recpt editor is the one that really gets the
2674                    focus. As it's inside a scrolled window, and this one inside the
2675                    hbox recpt editor inherits from, we'll need to go up in the 
2676                    hierarchy to know if the text view is part of the recpt editor
2677                    or if it's a different text entry */
2678
2679                 if (gtk_widget_get_parent (view_focus)) {
2680                         GtkWidget *first_parent;
2681
2682                         first_parent = gtk_widget_get_parent (view_focus);
2683                         if (gtk_widget_get_parent (first_parent) && 
2684                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2685                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2686                         }
2687                 }
2688
2689                 if (editor == NULL)
2690                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2691
2692         }
2693
2694         modest_address_book_select_addresses (editor);
2695
2696 }
2697
2698 void
2699 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2700 {
2701         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2702
2703         modest_msg_edit_window_open_addressbook (window, NULL);
2704 }
2705
2706 static void
2707 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2708                                      gboolean show_toolbar)
2709 {
2710         ModestWindowPrivate *parent_priv;
2711         const gchar *action_name;
2712         GtkAction *action;
2713         
2714         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2715         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2716
2717         /* We can not just use the code of
2718            modest_msg_edit_window_setup_toolbar because it has a
2719            mixture of both initialization and creation code. */
2720         if (show_toolbar)
2721                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2722         else
2723                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2724
2725         /* Update also the actions (to update the toggles in the
2726            menus), we have to do it manually because some other window
2727            of the same time could have changed it (remember that the
2728            toolbar fullscreen mode is shared by all the windows of the
2729            same type */
2730         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2731                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2732         else
2733                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2734         
2735         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2736         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2737                                                             show_toolbar);
2738
2739 }
2740
2741 void
2742 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2743                                            TnyHeaderFlags priority_flags)
2744 {
2745         ModestMsgEditWindowPrivate *priv;
2746         ModestWindowPrivate *parent_priv;
2747
2748         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2749
2750         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2751         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2752
2753         if (priv->priority_flags != priority_flags) {
2754                 GtkAction *priority_action = NULL;
2755
2756                 priv->priority_flags = priority_flags;
2757
2758                 switch (priority_flags) {
2759                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2760                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2761                         gtk_widget_show (priv->priority_icon);
2762                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2763                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2764                         break;
2765                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2766                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2767                         gtk_widget_show (priv->priority_icon);
2768                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2769                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2770                         break;
2771                 default:
2772                         gtk_widget_hide (priv->priority_icon);
2773                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2774                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2775                         break;
2776                 }
2777                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2778                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2779         }
2780 }
2781
2782 void
2783 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2784                                         gint file_format)
2785 {
2786         ModestMsgEditWindowPrivate *priv;
2787         ModestWindowPrivate *parent_priv;
2788         gint current_format;
2789
2790         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2791
2792         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2793         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2794
2795         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2796                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2797
2798         if (current_format != file_format) {
2799                 switch (file_format) {
2800                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2801                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2802                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2803                         break;
2804                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2805                 {
2806                         GtkWidget *dialog;
2807                         gint response;
2808                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2809                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2810                         gtk_widget_destroy (dialog);
2811                         if (response == GTK_RESPONSE_OK) {
2812                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2813                         } else {
2814                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2815                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2816                         }
2817                 }
2818                         break;
2819                 }
2820                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2821                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2822         }
2823 }
2824
2825 void
2826 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2827 {
2828         GtkWidget *dialog;
2829         ModestMsgEditWindowPrivate *priv;
2830         WPTextBufferFormat oldfmt, fmt;
2831         gint old_position = 0;
2832         gint response = 0;
2833         gint position = 0;
2834         gint font_size;
2835         GdkColor *color = NULL;
2836         gboolean bold, bold_set, italic, italic_set;
2837         gboolean underline, underline_set;
2838         gboolean strikethrough, strikethrough_set;
2839         gboolean position_set;
2840         gboolean font_size_set, font_set, color_set;
2841         gchar *font_name;
2842
2843         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2844         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2845         
2846         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2847         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2848                                      GTK_WINDOW(dialog));
2849
2850         /* First we get the currently selected font information */
2851         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2852
2853         switch (oldfmt.text_position) {
2854         case TEXT_POSITION_NORMAL:
2855                 old_position = 0;
2856                 break;
2857         case TEXT_POSITION_SUPERSCRIPT:
2858                 old_position = 1;
2859                 break;
2860         default:
2861                 old_position = -1;
2862                 break;
2863         }
2864
2865         g_object_set (G_OBJECT (dialog),
2866                       "bold", oldfmt.bold != FALSE,
2867                       "bold-set", !oldfmt.cs.bold,
2868                       "underline", oldfmt.underline != FALSE,
2869                       "underline-set", !oldfmt.cs.underline,
2870                       "italic", oldfmt.italic != FALSE,
2871                       "italic-set", !oldfmt.cs.italic,
2872                       "strikethrough", oldfmt.strikethrough != FALSE,
2873                       "strikethrough-set", !oldfmt.cs.strikethrough,
2874                       "color", &oldfmt.color,
2875                       "color-set", !oldfmt.cs.color,
2876                       "size", wp_font_size[oldfmt.font_size],
2877                       "size-set", !oldfmt.cs.font_size,
2878                       "position", old_position,
2879                       "position-set", !oldfmt.cs.text_position,
2880                       "family", wp_get_font_name (oldfmt.font),
2881                       "family-set", !oldfmt.cs.font,
2882                       NULL);
2883
2884         gtk_widget_show_all (dialog);
2885         priv->font_dialog = dialog;
2886         response = gtk_dialog_run (GTK_DIALOG (dialog));
2887         priv->font_dialog = NULL;
2888         if (response == GTK_RESPONSE_OK) {
2889
2890                 g_object_get( dialog,
2891                               "bold", &bold,
2892                               "bold-set", &bold_set,
2893                               "underline", &underline,
2894                               "underline-set", &underline_set,
2895                               "italic", &italic,
2896                               "italic-set", &italic_set,
2897                               "strikethrough", &strikethrough,
2898                               "strikethrough-set", &strikethrough_set,
2899                               "color", &color,
2900                               "color-set", &color_set,
2901                               "size", &font_size,
2902                               "size-set", &font_size_set,
2903                               "family", &font_name,
2904                               "family-set", &font_set,
2905                               "position", &position,
2906                               "position-set", &position_set,
2907                               NULL );
2908                 
2909         }       
2910
2911         if (response == GTK_RESPONSE_OK) {
2912                 memset(&fmt, 0, sizeof(fmt));
2913                 if (bold_set) {
2914                         fmt.bold = bold;
2915                         fmt.cs.bold = TRUE;
2916                 }
2917                 if (italic_set) {
2918                         fmt.italic = italic;
2919                         fmt.cs.italic = TRUE;
2920                 }
2921                 if (underline_set) {
2922                         fmt.underline = underline;
2923                         fmt.cs.underline = TRUE;
2924                 }
2925                 if (strikethrough_set) {
2926                         fmt.strikethrough = strikethrough;
2927                         fmt.cs.strikethrough = TRUE;
2928                 }
2929                 if (position_set) {
2930                         fmt.text_position =
2931                                 ( position == 0 )
2932                                 ? TEXT_POSITION_NORMAL
2933                                 : ( ( position == 1 )
2934                                     ? TEXT_POSITION_SUPERSCRIPT
2935                                     : TEXT_POSITION_SUBSCRIPT );
2936                         fmt.cs.text_position = TRUE;
2937                         fmt.font_size = oldfmt.font_size;
2938                 }
2939                 if (color_set) {
2940                         fmt.color = *color;
2941                         fmt.cs.color = TRUE;
2942                 }
2943                 if (font_set) {
2944                         fmt.font = wp_get_font_index(font_name,
2945                                                      DEFAULT_FONT);
2946                         fmt.cs.font = TRUE;
2947                 }
2948                 g_free(font_name);
2949                 if (font_size_set) {
2950                         fmt.cs.font_size = TRUE;
2951                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2952                 }
2953                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2954                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2955         }
2956         gtk_widget_destroy (dialog);
2957         
2958         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2959 }
2960
2961 void
2962 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2963 {
2964         ModestMsgEditWindowPrivate *priv;
2965
2966         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2967         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2968         
2969         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2970
2971         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2972         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2973
2974 }
2975
2976 void
2977 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2978 {
2979         ModestMsgEditWindowPrivate *priv;
2980
2981         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2982         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2983         
2984         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2985
2986         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2987         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2988
2989 }
2990
2991 static void  
2992 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2993 {
2994         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2995
2996         priv->can_undo = can_undo;
2997 }
2998
2999 static void  
3000 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3001 {
3002         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3003
3004         priv->can_redo = can_redo;
3005 }
3006
3007 gboolean            
3008 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3009 {
3010         ModestMsgEditWindowPrivate *priv;
3011         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3012         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3013
3014         return priv->can_undo;
3015 }
3016
3017 gboolean            
3018 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3019 {
3020         ModestMsgEditWindowPrivate *priv;
3021         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3022         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3023
3024         return priv->can_redo;
3025 }
3026
3027
3028 static void
3029 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3030 {
3031         GtkTextIter iter;
3032         GtkTextIter match_start, match_end;
3033
3034         if (image_id == NULL)
3035                 return;
3036
3037         gtk_text_buffer_get_start_iter (buffer, &iter);
3038
3039         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3040                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3041                 GSList *node;
3042                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3043                         GtkTextTag *tag = (GtkTextTag *) node->data;
3044                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3045                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3046                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3047                                         gint offset;
3048                                         offset = gtk_text_iter_get_offset (&match_start);
3049                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3050                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3051                                 }
3052                         }
3053                 }
3054                 gtk_text_iter_forward_char (&iter);
3055         }
3056 }
3057
3058 gboolean
3059 message_is_empty (ModestMsgEditWindow *window)
3060 {
3061         ModestMsgEditWindowPrivate *priv = NULL;
3062
3063         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3064         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3065
3066         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3067          * so we can ignore markup.
3068          */
3069         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3070         gint count = 0;
3071         if (buf)
3072                 count = gtk_text_buffer_get_char_count (buf);
3073
3074         return count == 0;
3075 }
3076
3077 static gboolean
3078 msg_body_focus (GtkWidget *focus,
3079                 GdkEventFocus *event,
3080                 gpointer userdata)
3081 {
3082         
3083         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3084         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3085         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3086         return FALSE;
3087 }
3088
3089 static void
3090 recpt_field_changed (GtkTextBuffer *buffer,
3091                   ModestMsgEditWindow *editor)
3092 {
3093         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3094         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3095 }
3096
3097 static void
3098 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3099 {
3100         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3101         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3102 }
3103
3104 void
3105 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3106                                      gboolean modified)
3107 {
3108         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3109         GtkTextBuffer *buffer;
3110
3111         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3112         gtk_text_buffer_set_modified (buffer, modified);
3113         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3114         gtk_text_buffer_set_modified (buffer, modified);
3115         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3116         gtk_text_buffer_set_modified (buffer, modified);
3117         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3118 }
3119
3120 gboolean
3121 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3122 {
3123         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3124         const char *account_name;
3125         GtkTextBuffer *buffer;
3126
3127         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3128         if (gtk_text_buffer_get_modified (buffer))
3129                 return TRUE;
3130         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3131         if (gtk_text_buffer_get_modified (buffer))
3132                 return TRUE;
3133         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3134         if (gtk_text_buffer_get_modified (buffer))
3135                 return TRUE;
3136         if (gtk_text_buffer_get_modified (priv->text_buffer))
3137                 return TRUE;
3138         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
3139         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3140                 return TRUE;
3141         }
3142
3143         return FALSE;
3144 }
3145
3146
3147
3148
3149 gboolean
3150 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3151 {
3152         ModestMsgEditWindowPrivate *priv = NULL;
3153         
3154         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3155         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3156
3157         /* check if there's no recipient added */
3158         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3159             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3160             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3161                 /* no recipient contents, then select contacts */
3162                 modest_msg_edit_window_open_addressbook (window, NULL);
3163                 return FALSE;
3164         }
3165
3166         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3167                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3168                 return FALSE;
3169         }
3170         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3171                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3172                 return FALSE;
3173         }
3174         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3175                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3176                 return FALSE;
3177         }
3178
3179         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3180             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3181                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3182
3183         return TRUE;
3184
3185 }
3186
3187 static void
3188 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3189                                                ModestMsgEditWindow *window)
3190 {
3191         modest_msg_edit_window_offer_attach_file (window);
3192 }
3193
3194 const gchar *
3195 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3196 {
3197         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3198
3199         return priv->clipboard_text;
3200 }
3201
3202 static void
3203 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3204                                                GdkEvent *event,
3205                                                ModestMsgEditWindow *window)
3206 {
3207         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3208         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3209         gchar *text = NULL;
3210         if (!GTK_WIDGET_VISIBLE (window))
3211                 return;
3212
3213         g_object_ref (window);
3214         text = gtk_clipboard_wait_for_text (selection_clipboard);
3215
3216         if (priv->clipboard_text != NULL) {
3217                 g_free (priv->clipboard_text);
3218         }
3219         priv->clipboard_text = text;
3220
3221         if (GTK_WIDGET_VISIBLE (window)) {
3222                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3223         }
3224         g_object_unref (window);
3225 }
3226
3227 static gboolean clipboard_owner_change_idle (gpointer userdata)
3228 {
3229         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3230         ModestMsgEditWindowPrivate *priv;
3231
3232         gdk_threads_enter ();
3233         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3234         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3235
3236         priv->clipboard_owner_idle = 0;
3237         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3238         gdk_threads_leave ();
3239
3240         return FALSE;
3241 }
3242
3243 static void
3244 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3245 {
3246         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3247         if (priv->clipboard_owner_idle == 0) {
3248                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3249         }
3250 }
3251
3252 static void 
3253 subject_field_move_cursor (GtkEntry *entry,
3254                            GtkMovementStep step,
3255                            gint a1,
3256                            gboolean a2,
3257                            gpointer window)
3258 {
3259         if (!GTK_WIDGET_VISIBLE (window))
3260                 return;
3261
3262         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3263 }
3264
3265 static void 
3266 update_window_title (ModestMsgEditWindow *window)
3267 {
3268         ModestMsgEditWindowPrivate *priv = NULL;
3269         const gchar *subject;
3270
3271         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3272         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3273         if (subject == NULL || subject[0] == '\0')
3274                 subject = _("mail_va_new_email");
3275
3276         gtk_window_set_title (GTK_WINDOW (window), subject);
3277
3278 }
3279
3280 static void  
3281 subject_field_changed (GtkEditable *editable, 
3282                        ModestMsgEditWindow *window)
3283 {
3284         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3285         update_window_title (window);
3286         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3287         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3288         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3289 }
3290
3291 static void  
3292 subject_field_insert_text (GtkEditable *editable, 
3293                            gchar *new_text,
3294                            gint new_text_length,
3295                            gint *position,
3296                            ModestMsgEditWindow *window)
3297 {
3298         GString *result = g_string_new ("");
3299         gchar *current;
3300         gint result_len = 0;
3301         const gchar *entry_text = NULL;
3302         gint old_length;
3303
3304         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3305         old_length = g_utf8_strlen (entry_text, -1);
3306
3307         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3308                 gunichar c = g_utf8_get_char_validated (current, 8);
3309                 /* Invalid unichar, stop */
3310                 if (c == -1)
3311                         break;
3312                 /* a bullet */
3313                 if (c == 0x2022)
3314                         continue;
3315                 result = g_string_append_unichar (result, c);
3316                 result_len++;
3317         }
3318
3319         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3320                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3321                 if (result_len > 0)
3322                 {
3323                         /* Prevent endless recursion */
3324                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3325                         g_signal_emit_by_name (editable, "insert-text", 
3326                                                (gpointer) result->str, (gpointer) result->len,
3327                                                (gpointer) position, (gpointer) window);
3328                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3329                 }
3330         }
3331
3332         if (result_len + old_length > 1000) {
3333                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3334                                                 dgettext("hildon-common-strings",
3335                                                          "ckdg_ib_maximum_characters_reached"));
3336         }
3337         
3338         g_string_free (result, TRUE);
3339 }
3340
3341 static void  
3342 text_buffer_insert_text (GtkTextBuffer *buffer, 
3343                          GtkTextIter *iter,
3344                          gchar *new_text,
3345                          gint new_text_length,
3346                          ModestMsgEditWindow *window)
3347 {
3348         GString *result = g_string_new ("");
3349         gchar *current;
3350         gint result_len = 0;
3351         gboolean changed = FALSE;
3352
3353         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3354                 gunichar c = g_utf8_get_char_validated (current, 8);
3355                 /* Invalid unichar, stop */
3356                 if (c == -1)
3357                         break;
3358                 /* a bullet */
3359                 switch (c) {
3360                 case 0x2022:
3361                         result = g_string_append_c (result, ' ');
3362                         changed = TRUE;
3363                         break;
3364                 default:
3365                         result = g_string_append_unichar (result, c);
3366                 }
3367                 result_len++;
3368         }
3369
3370         if (changed) {
3371                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3372                 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3373                 g_signal_emit_by_name (buffer, "insert-text", 
3374                                        (gpointer) iter,
3375                                        (gpointer) result->str, (gpointer) result->len,
3376                                        (gpointer) window);
3377                 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3378         }
3379
3380         g_string_free (result, TRUE);
3381 }
3382
3383 void
3384 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3385                                             gboolean show)
3386 {
3387         ModestMsgEditWindowPrivate *priv = NULL;
3388
3389         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3390         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3391
3392         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3393
3394         if (show) {
3395                 gtk_widget_show_all (priv->find_toolbar);
3396                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3397         } else {
3398                 gtk_widget_hide_all (priv->find_toolbar);
3399                 gtk_widget_grab_focus (priv->msg_body);
3400         }
3401     
3402 }
3403
3404 static gboolean 
3405 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3406                                           const gchar *str,
3407                                           GtkTextIter *match_start,
3408                                           GtkTextIter *match_end)
3409 {
3410         GtkTextIter end_iter;
3411         gchar *str_casefold;
3412         gint str_chars_n;
3413         gchar *range_text;
3414         gchar *range_casefold;
3415         gint offset;
3416         gint range_chars_n;
3417         gboolean result = FALSE;
3418
3419         if (str == NULL)
3420                 return TRUE;
3421         
3422         /* get end iter */
3423         end_iter = *iter;
3424         gtk_text_iter_forward_to_end (&end_iter);
3425
3426         str_casefold = g_utf8_casefold (str, -1);
3427         str_chars_n = strlen (str);
3428
3429         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3430         range_casefold = g_utf8_casefold (range_text, -1);
3431         range_chars_n = strlen (range_casefold);
3432
3433         if (range_chars_n < str_chars_n) {
3434                 g_free (str_casefold);
3435                 g_free (range_text);
3436                 g_free (range_casefold);
3437                 return FALSE;
3438         }
3439
3440         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3441                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3442                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3443                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3444                         result = TRUE;
3445                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3446                                                       match_start, match_end, NULL);
3447                         g_free (found_text);
3448                 }
3449                 g_free (range_subtext);
3450                 if (result)
3451                         break;
3452         }
3453         g_free (str_casefold);
3454         g_free (range_text);
3455         g_free (range_casefold);
3456
3457         return result;
3458 }
3459
3460
3461 static void 
3462 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3463                                             ModestMsgEditWindow *window)
3464 {
3465         gchar *current_search = NULL;
3466         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3467         gboolean result;
3468         GtkTextIter selection_start, selection_end;
3469         GtkTextIter match_start, match_end;
3470         gboolean continue_search = FALSE;
3471
3472         if (message_is_empty (window)) {
3473                 g_free (priv->last_search);
3474                 priv->last_search = NULL;
3475                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3476                 return;
3477         }
3478
3479         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3480         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3481                 g_free (current_search);
3482                 g_free (priv->last_search);
3483                 priv->last_search = NULL;
3484                 /* Information banner about empty search */
3485                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3486                 return;
3487         }
3488
3489         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3490                 continue_search = TRUE;
3491         } else {
3492                 g_free (priv->last_search);
3493                 priv->last_search = g_strdup (current_search);
3494         }
3495
3496         if (continue_search) {
3497                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3498                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3499                                                                    &match_start, &match_end);
3500                 if (!result)
3501                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3502         } else {
3503                 GtkTextIter buffer_start;
3504                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3505                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3506                                                                    &match_start, &match_end);
3507                 if (!result)
3508                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3509         }
3510
3511         /* Mark as selected the string found in search */
3512         if (result) {
3513                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3514                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3515                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3516         } else {
3517                 g_free (priv->last_search);
3518                 priv->last_search = NULL;
3519         }
3520         g_free (current_search);
3521 }
3522
3523 static void
3524 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3525                                            ModestMsgEditWindow *window)
3526 {
3527         GtkToggleAction *toggle;
3528         ModestWindowPrivate *parent_priv;
3529         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3530
3531         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3532         gtk_toggle_action_set_active (toggle, FALSE);
3533 }
3534
3535 gboolean 
3536 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3537 {
3538         ModestMsgEditWindowPrivate *priv;
3539
3540         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3541         return priv->sent;
3542 }
3543
3544 void 
3545 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3546                                  gboolean sent)
3547 {
3548         ModestMsgEditWindowPrivate *priv;
3549
3550         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3551         priv->sent = sent;
3552 }
3553
3554
3555 void            
3556 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3557                                   TnyMsg *draft)
3558 {
3559         ModestMsgEditWindowPrivate *priv;
3560         TnyHeader *header = NULL;
3561
3562         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3563         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3564
3565         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3566         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3567
3568         if (priv->draft_msg != NULL) {
3569                 g_object_unref (priv->draft_msg);
3570         }
3571
3572         if (draft != NULL) {
3573                 g_object_ref (draft);
3574                 header = tny_msg_get_header (draft);
3575                 if (priv->msg_uid) {
3576                         g_free (priv->msg_uid);
3577                         priv->msg_uid = NULL;
3578                 }
3579                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3580                 if (GTK_WIDGET_REALIZED (window))
3581                         modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3582         }
3583
3584         priv->draft_msg = draft;
3585 }
3586
3587 static void  
3588 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3589                        GtkTextIter *start, GtkTextIter *end,
3590                        gpointer userdata)
3591 {
3592         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3593         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3594         gchar *tag_name;
3595
3596         if (tag == NULL+13) return;
3597         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3598         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3599                 replace_with_images (window, priv->images);
3600         }
3601 }
3602
3603 void                    
3604 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3605                                  TnyMimePart *part)
3606 {
3607         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3608
3609         g_return_if_fail (TNY_IS_MIME_PART (part));
3610         tny_list_prepend (priv->attachments, (GObject *) part);
3611         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3612         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3613         gtk_widget_show_all (priv->attachments_caption);
3614         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3615 }
3616
3617 const gchar*    
3618 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3619 {
3620         ModestMsgEditWindowPrivate *priv;
3621
3622         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3623         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3624
3625         return priv->msg_uid;
3626 }
3627
3628 GtkWidget *
3629 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3630                                          ModestMsgEditWindowWidgetType widget_type)
3631 {
3632         ModestMsgEditWindowPrivate *priv;
3633
3634         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3635         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3636
3637         switch (widget_type) {
3638         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3639                 return priv->msg_body;
3640                 break;
3641         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3642                 return priv->to_field;
3643                 break;
3644         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3645                 return priv->cc_field;
3646                 break;
3647         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3648                 return priv->bcc_field;
3649                 break;
3650         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3651                 return priv->subject_field;
3652                 break;
3653         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3654                 return priv->attachments_view;
3655                 break;
3656         default:
3657                 return NULL;
3658         }
3659 }
3660
3661 static void 
3662 remove_tags (WPTextBuffer *buffer)
3663 {
3664         GtkTextIter start, end;
3665
3666         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3667         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3668
3669         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3670 }
3671
3672 static void
3673 on_account_removed (TnyAccountStore *account_store, 
3674                     TnyAccount *account,
3675                     gpointer user_data)
3676 {
3677         /* Do nothing if it's a store account, because we use the
3678            transport to send the messages */
3679         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3680                 const gchar *parent_acc = NULL;
3681                 const gchar *our_acc = NULL;
3682
3683                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3684                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3685                 /* Close this window if I'm showing a message of the removed account */
3686                 if (strcmp (parent_acc, our_acc) == 0)
3687                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3688         }
3689 }
3690
3691 static gboolean
3692 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3693 {
3694         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3695
3696         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3697         return FALSE;
3698
3699 }
3700
3701 static void
3702 set_zoom_do_nothing (ModestWindow *window,
3703                                  gdouble zoom)
3704 {
3705 }
3706
3707 static gdouble
3708 get_zoom_do_nothing (ModestWindow *window)
3709 {
3710         return 1.0;
3711 }
3712