* Reverted changes for bug 85454 since it adds another bugs
[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), TRUE))
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), TRUE))
2663                 return;
2664
2665         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2666
2667         if (editor == NULL) {
2668                 GtkWidget *view_focus;
2669                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2670
2671                 /* This code should be kept in sync with ModestRecptEditor. The
2672                    textview inside the recpt editor is the one that really gets the
2673                    focus. As it's inside a scrolled window, and this one inside the
2674                    hbox recpt editor inherits from, we'll need to go up in the 
2675                    hierarchy to know if the text view is part of the recpt editor
2676                    or if it's a different text entry */
2677
2678                 if (gtk_widget_get_parent (view_focus)) {
2679                         GtkWidget *first_parent;
2680
2681                         first_parent = gtk_widget_get_parent (view_focus);
2682                         if (gtk_widget_get_parent (first_parent) && 
2683                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2684                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2685                         }
2686                 }
2687
2688                 if (editor == NULL)
2689                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2690
2691         }
2692
2693         modest_address_book_select_addresses (editor);
2694
2695 }
2696
2697 void
2698 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2699 {
2700         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2701
2702         modest_msg_edit_window_open_addressbook (window, NULL);
2703 }
2704
2705 static void
2706 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2707                                      gboolean show_toolbar)
2708 {
2709         ModestWindowPrivate *parent_priv;
2710         const gchar *action_name;
2711         GtkAction *action;
2712         
2713         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2714         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2715
2716         /* We can not just use the code of
2717            modest_msg_edit_window_setup_toolbar because it has a
2718            mixture of both initialization and creation code. */
2719         if (show_toolbar)
2720                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2721         else
2722                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2723
2724         /* Update also the actions (to update the toggles in the
2725            menus), we have to do it manually because some other window
2726            of the same time could have changed it (remember that the
2727            toolbar fullscreen mode is shared by all the windows of the
2728            same type */
2729         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2730                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2731         else
2732                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2733         
2734         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2735         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2736                                                             show_toolbar);
2737
2738 }
2739
2740 void
2741 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2742                                            TnyHeaderFlags priority_flags)
2743 {
2744         ModestMsgEditWindowPrivate *priv;
2745         ModestWindowPrivate *parent_priv;
2746
2747         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2748
2749         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2750         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2751
2752         if (priv->priority_flags != priority_flags) {
2753                 GtkAction *priority_action = NULL;
2754
2755                 priv->priority_flags = priority_flags;
2756
2757                 switch (priority_flags) {
2758                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2759                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2760                         gtk_widget_show (priv->priority_icon);
2761                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2762                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2763                         break;
2764                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2765                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2766                         gtk_widget_show (priv->priority_icon);
2767                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2768                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2769                         break;
2770                 default:
2771                         gtk_widget_hide (priv->priority_icon);
2772                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2773                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2774                         break;
2775                 }
2776                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2777                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2778         }
2779 }
2780
2781 void
2782 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2783                                         gint file_format)
2784 {
2785         ModestMsgEditWindowPrivate *priv;
2786         ModestWindowPrivate *parent_priv;
2787         gint current_format;
2788
2789         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2790
2791         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2792         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2793
2794         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2795                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2796
2797         if (current_format != file_format) {
2798                 switch (file_format) {
2799                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2800                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2801                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2802                         break;
2803                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2804                 {
2805                         GtkWidget *dialog;
2806                         gint response;
2807                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2808                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2809                         gtk_widget_destroy (dialog);
2810                         if (response == GTK_RESPONSE_OK) {
2811                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2812                         } else {
2813                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2814                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2815                         }
2816                 }
2817                         break;
2818                 }
2819                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2820                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2821         }
2822 }
2823
2824 void
2825 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2826 {
2827         GtkWidget *dialog;
2828         ModestMsgEditWindowPrivate *priv;
2829         WPTextBufferFormat oldfmt, fmt;
2830         gint old_position = 0;
2831         gint response = 0;
2832         gint position = 0;
2833         gint font_size;
2834         GdkColor *color = NULL;
2835         gboolean bold, bold_set, italic, italic_set;
2836         gboolean underline, underline_set;
2837         gboolean strikethrough, strikethrough_set;
2838         gboolean position_set;
2839         gboolean font_size_set, font_set, color_set;
2840         gchar *font_name;
2841
2842         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2843         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2844         
2845         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2846         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2847                                      GTK_WINDOW(dialog));
2848
2849         /* First we get the currently selected font information */
2850         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2851
2852         switch (oldfmt.text_position) {
2853         case TEXT_POSITION_NORMAL:
2854                 old_position = 0;
2855                 break;
2856         case TEXT_POSITION_SUPERSCRIPT:
2857                 old_position = 1;
2858                 break;
2859         default:
2860                 old_position = -1;
2861                 break;
2862         }
2863
2864         g_object_set (G_OBJECT (dialog),
2865                       "bold", oldfmt.bold != FALSE,
2866                       "bold-set", !oldfmt.cs.bold,
2867                       "underline", oldfmt.underline != FALSE,
2868                       "underline-set", !oldfmt.cs.underline,
2869                       "italic", oldfmt.italic != FALSE,
2870                       "italic-set", !oldfmt.cs.italic,
2871                       "strikethrough", oldfmt.strikethrough != FALSE,
2872                       "strikethrough-set", !oldfmt.cs.strikethrough,
2873                       "color", &oldfmt.color,
2874                       "color-set", !oldfmt.cs.color,
2875                       "size", wp_font_size[oldfmt.font_size],
2876                       "size-set", !oldfmt.cs.font_size,
2877                       "position", old_position,
2878                       "position-set", !oldfmt.cs.text_position,
2879                       "family", wp_get_font_name (oldfmt.font),
2880                       "family-set", !oldfmt.cs.font,
2881                       NULL);
2882
2883         gtk_widget_show_all (dialog);
2884         priv->font_dialog = dialog;
2885         response = gtk_dialog_run (GTK_DIALOG (dialog));
2886         priv->font_dialog = NULL;
2887         if (response == GTK_RESPONSE_OK) {
2888
2889                 g_object_get( dialog,
2890                               "bold", &bold,
2891                               "bold-set", &bold_set,
2892                               "underline", &underline,
2893                               "underline-set", &underline_set,
2894                               "italic", &italic,
2895                               "italic-set", &italic_set,
2896                               "strikethrough", &strikethrough,
2897                               "strikethrough-set", &strikethrough_set,
2898                               "color", &color,
2899                               "color-set", &color_set,
2900                               "size", &font_size,
2901                               "size-set", &font_size_set,
2902                               "family", &font_name,
2903                               "family-set", &font_set,
2904                               "position", &position,
2905                               "position-set", &position_set,
2906                               NULL );
2907                 
2908         }       
2909
2910         if (response == GTK_RESPONSE_OK) {
2911                 memset(&fmt, 0, sizeof(fmt));
2912                 if (bold_set) {
2913                         fmt.bold = bold;
2914                         fmt.cs.bold = TRUE;
2915                 }
2916                 if (italic_set) {
2917                         fmt.italic = italic;
2918                         fmt.cs.italic = TRUE;
2919                 }
2920                 if (underline_set) {
2921                         fmt.underline = underline;
2922                         fmt.cs.underline = TRUE;
2923                 }
2924                 if (strikethrough_set) {
2925                         fmt.strikethrough = strikethrough;
2926                         fmt.cs.strikethrough = TRUE;
2927                 }
2928                 if (position_set) {
2929                         fmt.text_position =
2930                                 ( position == 0 )
2931                                 ? TEXT_POSITION_NORMAL
2932                                 : ( ( position == 1 )
2933                                     ? TEXT_POSITION_SUPERSCRIPT
2934                                     : TEXT_POSITION_SUBSCRIPT );
2935                         fmt.cs.text_position = TRUE;
2936                         fmt.font_size = oldfmt.font_size;
2937                 }
2938                 if (color_set) {
2939                         fmt.color = *color;
2940                         fmt.cs.color = TRUE;
2941                 }
2942                 if (font_set) {
2943                         fmt.font = wp_get_font_index(font_name,
2944                                                      DEFAULT_FONT);
2945                         fmt.cs.font = TRUE;
2946                 }
2947                 g_free(font_name);
2948                 if (font_size_set) {
2949                         fmt.cs.font_size = TRUE;
2950                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2951                 }
2952                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2953                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2954         }
2955         gtk_widget_destroy (dialog);
2956         
2957         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2958 }
2959
2960 void
2961 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2962 {
2963         ModestMsgEditWindowPrivate *priv;
2964
2965         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2966         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2967         
2968         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2969
2970         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2971         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2972
2973 }
2974
2975 void
2976 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2977 {
2978         ModestMsgEditWindowPrivate *priv;
2979
2980         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2981         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982         
2983         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2984
2985         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2986         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2987
2988 }
2989
2990 static void  
2991 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2992 {
2993         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2994
2995         priv->can_undo = can_undo;
2996 }
2997
2998 static void  
2999 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3000 {
3001         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3002
3003         priv->can_redo = can_redo;
3004 }
3005
3006 gboolean            
3007 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3008 {
3009         ModestMsgEditWindowPrivate *priv;
3010         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3011         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3012
3013         return priv->can_undo;
3014 }
3015
3016 gboolean            
3017 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3018 {
3019         ModestMsgEditWindowPrivate *priv;
3020         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3021         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3022
3023         return priv->can_redo;
3024 }
3025
3026
3027 static void
3028 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3029 {
3030         GtkTextIter iter;
3031         GtkTextIter match_start, match_end;
3032
3033         if (image_id == NULL)
3034                 return;
3035
3036         gtk_text_buffer_get_start_iter (buffer, &iter);
3037
3038         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3039                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3040                 GSList *node;
3041                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3042                         GtkTextTag *tag = (GtkTextTag *) node->data;
3043                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3044                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3045                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3046                                         gint offset;
3047                                         offset = gtk_text_iter_get_offset (&match_start);
3048                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3049                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3050                                 }
3051                         }
3052                 }
3053                 gtk_text_iter_forward_char (&iter);
3054         }
3055 }
3056
3057 gboolean
3058 message_is_empty (ModestMsgEditWindow *window)
3059 {
3060         ModestMsgEditWindowPrivate *priv = NULL;
3061
3062         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3063         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3064
3065         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3066          * so we can ignore markup.
3067          */
3068         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3069         gint count = 0;
3070         if (buf)
3071                 count = gtk_text_buffer_get_char_count (buf);
3072
3073         return count == 0;
3074 }
3075
3076 static gboolean
3077 msg_body_focus (GtkWidget *focus,
3078                 GdkEventFocus *event,
3079                 gpointer userdata)
3080 {
3081         
3082         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3083         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3084         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3085         return FALSE;
3086 }
3087
3088 static void
3089 recpt_field_changed (GtkTextBuffer *buffer,
3090                   ModestMsgEditWindow *editor)
3091 {
3092         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3093         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3094 }
3095
3096 static void
3097 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3098 {
3099         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3100         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3101 }
3102
3103 void
3104 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3105                                      gboolean modified)
3106 {
3107         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3108         GtkTextBuffer *buffer;
3109
3110         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3111         gtk_text_buffer_set_modified (buffer, modified);
3112         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3113         gtk_text_buffer_set_modified (buffer, modified);
3114         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3115         gtk_text_buffer_set_modified (buffer, modified);
3116         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3117 }
3118
3119 gboolean
3120 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3121 {
3122         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3123         const char *account_name;
3124         GtkTextBuffer *buffer;
3125
3126         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3127         if (gtk_text_buffer_get_modified (buffer))
3128                 return TRUE;
3129         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3130         if (gtk_text_buffer_get_modified (buffer))
3131                 return TRUE;
3132         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3133         if (gtk_text_buffer_get_modified (buffer))
3134                 return TRUE;
3135         if (gtk_text_buffer_get_modified (priv->text_buffer))
3136                 return TRUE;
3137         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
3138         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3139                 return TRUE;
3140         }
3141
3142         return FALSE;
3143 }
3144
3145
3146
3147
3148 gboolean
3149 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3150 {
3151         ModestMsgEditWindowPrivate *priv = NULL;
3152         
3153         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3154         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3155
3156         /* check if there's no recipient added */
3157         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3158             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3159             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3160                 /* no recipient contents, then select contacts */
3161                 modest_msg_edit_window_open_addressbook (window, NULL);
3162                 return FALSE;
3163         }
3164
3165         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3166                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3167                 return FALSE;
3168         }
3169         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3170                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3171                 return FALSE;
3172         }
3173         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3174                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3175                 return FALSE;
3176         }
3177
3178         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3179             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3180                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3181
3182         return TRUE;
3183
3184 }
3185
3186 static void
3187 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3188                                                ModestMsgEditWindow *window)
3189 {
3190         modest_msg_edit_window_offer_attach_file (window);
3191 }
3192
3193 const gchar *
3194 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3195 {
3196         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3197
3198         return priv->clipboard_text;
3199 }
3200
3201 static void
3202 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3203                                                GdkEvent *event,
3204                                                ModestMsgEditWindow *window)
3205 {
3206         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3207         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3208         gchar *text = NULL;
3209         if (!GTK_WIDGET_VISIBLE (window))
3210                 return;
3211
3212         g_object_ref (window);
3213         text = gtk_clipboard_wait_for_text (selection_clipboard);
3214
3215         if (priv->clipboard_text != NULL) {
3216                 g_free (priv->clipboard_text);
3217         }
3218         priv->clipboard_text = text;
3219
3220         if (GTK_WIDGET_VISIBLE (window)) {
3221                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3222         }
3223         g_object_unref (window);
3224 }
3225
3226 static gboolean clipboard_owner_change_idle (gpointer userdata)
3227 {
3228         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3229         ModestMsgEditWindowPrivate *priv;
3230
3231         gdk_threads_enter ();
3232         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3233         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3234
3235         priv->clipboard_owner_idle = 0;
3236         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3237         gdk_threads_leave ();
3238
3239         return FALSE;
3240 }
3241
3242 static void
3243 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3244 {
3245         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3246         if (priv->clipboard_owner_idle == 0) {
3247                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3248         }
3249 }
3250
3251 static void 
3252 subject_field_move_cursor (GtkEntry *entry,
3253                            GtkMovementStep step,
3254                            gint a1,
3255                            gboolean a2,
3256                            gpointer window)
3257 {
3258         if (!GTK_WIDGET_VISIBLE (window))
3259                 return;
3260
3261         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3262 }
3263
3264 static void 
3265 update_window_title (ModestMsgEditWindow *window)
3266 {
3267         ModestMsgEditWindowPrivate *priv = NULL;
3268         const gchar *subject;
3269
3270         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3271         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3272         if (subject == NULL || subject[0] == '\0')
3273                 subject = _("mail_va_new_email");
3274
3275         gtk_window_set_title (GTK_WINDOW (window), subject);
3276
3277 }
3278
3279 static void  
3280 subject_field_changed (GtkEditable *editable, 
3281                        ModestMsgEditWindow *window)
3282 {
3283         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3284         update_window_title (window);
3285         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3286         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3287         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3288 }
3289
3290 static void  
3291 subject_field_insert_text (GtkEditable *editable, 
3292                            gchar *new_text,
3293                            gint new_text_length,
3294                            gint *position,
3295                            ModestMsgEditWindow *window)
3296 {
3297         GString *result = g_string_new ("");
3298         gchar *current;
3299         gint result_len = 0;
3300         const gchar *entry_text = NULL;
3301         gint old_length;
3302
3303         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3304         old_length = g_utf8_strlen (entry_text, -1);
3305
3306         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3307                 gunichar c = g_utf8_get_char_validated (current, 8);
3308                 /* Invalid unichar, stop */
3309                 if (c == -1)
3310                         break;
3311                 /* a bullet */
3312                 if (c == 0x2022)
3313                         continue;
3314                 result = g_string_append_unichar (result, c);
3315                 result_len++;
3316         }
3317
3318         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3319                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3320                 if (result_len > 0)
3321                 {
3322                         /* Prevent endless recursion */
3323                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3324                         g_signal_emit_by_name (editable, "insert-text", 
3325                                                (gpointer) result->str, (gpointer) result->len,
3326                                                (gpointer) position, (gpointer) window);
3327                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3328                 }
3329         }
3330
3331         if (result_len + old_length > 1000) {
3332                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3333                                                 dgettext("hildon-common-strings",
3334                                                          "ckdg_ib_maximum_characters_reached"));
3335         }
3336         
3337         g_string_free (result, TRUE);
3338 }
3339
3340 static void  
3341 text_buffer_insert_text (GtkTextBuffer *buffer, 
3342                          GtkTextIter *iter,
3343                          gchar *new_text,
3344                          gint new_text_length,
3345                          ModestMsgEditWindow *window)
3346 {
3347         GString *result = g_string_new ("");
3348         gchar *current;
3349         gint result_len = 0;
3350         gboolean changed = FALSE;
3351
3352         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3353                 gunichar c = g_utf8_get_char_validated (current, 8);
3354                 /* Invalid unichar, stop */
3355                 if (c == -1)
3356                         break;
3357                 /* a bullet */
3358                 switch (c) {
3359                 case 0x2022:
3360                         result = g_string_append_c (result, ' ');
3361                         changed = TRUE;
3362                         break;
3363                 default:
3364                         result = g_string_append_unichar (result, c);
3365                 }
3366                 result_len++;
3367         }
3368
3369         if (changed) {
3370                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3371                 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3372                 g_signal_emit_by_name (buffer, "insert-text", 
3373                                        (gpointer) iter,
3374                                        (gpointer) result->str, (gpointer) result->len,
3375                                        (gpointer) window);
3376                 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3377         }
3378
3379         g_string_free (result, TRUE);
3380 }
3381
3382 void
3383 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3384                                             gboolean show)
3385 {
3386         ModestMsgEditWindowPrivate *priv = NULL;
3387
3388         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3389         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3390
3391         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3392
3393         if (show) {
3394                 gtk_widget_show_all (priv->find_toolbar);
3395                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3396         } else {
3397                 gtk_widget_hide_all (priv->find_toolbar);
3398                 gtk_widget_grab_focus (priv->msg_body);
3399         }
3400     
3401 }
3402
3403 static gboolean 
3404 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3405                                           const gchar *str,
3406                                           GtkTextIter *match_start,
3407                                           GtkTextIter *match_end)
3408 {
3409         GtkTextIter end_iter;
3410         gchar *str_casefold;
3411         gint str_chars_n;
3412         gchar *range_text;
3413         gchar *range_casefold;
3414         gint offset;
3415         gint range_chars_n;
3416         gboolean result = FALSE;
3417
3418         if (str == NULL)
3419                 return TRUE;
3420         
3421         /* get end iter */
3422         end_iter = *iter;
3423         gtk_text_iter_forward_to_end (&end_iter);
3424
3425         str_casefold = g_utf8_casefold (str, -1);
3426         str_chars_n = strlen (str);
3427
3428         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3429         range_casefold = g_utf8_casefold (range_text, -1);
3430         range_chars_n = strlen (range_casefold);
3431
3432         if (range_chars_n < str_chars_n) {
3433                 g_free (str_casefold);
3434                 g_free (range_text);
3435                 g_free (range_casefold);
3436                 return FALSE;
3437         }
3438
3439         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3440                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3441                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3442                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3443                         result = TRUE;
3444                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3445                                                       match_start, match_end, NULL);
3446                         g_free (found_text);
3447                 }
3448                 g_free (range_subtext);
3449                 if (result)
3450                         break;
3451         }
3452         g_free (str_casefold);
3453         g_free (range_text);
3454         g_free (range_casefold);
3455
3456         return result;
3457 }
3458
3459
3460 static void 
3461 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3462                                             ModestMsgEditWindow *window)
3463 {
3464         gchar *current_search = NULL;
3465         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3466         gboolean result;
3467         GtkTextIter selection_start, selection_end;
3468         GtkTextIter match_start, match_end;
3469         gboolean continue_search = FALSE;
3470
3471         if (message_is_empty (window)) {
3472                 g_free (priv->last_search);
3473                 priv->last_search = NULL;
3474                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3475                 return;
3476         }
3477
3478         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3479         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3480                 g_free (current_search);
3481                 g_free (priv->last_search);
3482                 priv->last_search = NULL;
3483                 /* Information banner about empty search */
3484                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3485                 return;
3486         }
3487
3488         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3489                 continue_search = TRUE;
3490         } else {
3491                 g_free (priv->last_search);
3492                 priv->last_search = g_strdup (current_search);
3493         }
3494
3495         if (continue_search) {
3496                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3497                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3498                                                                    &match_start, &match_end);
3499                 if (!result)
3500                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3501         } else {
3502                 GtkTextIter buffer_start;
3503                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3504                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3505                                                                    &match_start, &match_end);
3506                 if (!result)
3507                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3508         }
3509
3510         /* Mark as selected the string found in search */
3511         if (result) {
3512                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3513                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3514                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3515         } else {
3516                 g_free (priv->last_search);
3517                 priv->last_search = NULL;
3518         }
3519         g_free (current_search);
3520 }
3521
3522 static void
3523 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3524                                            ModestMsgEditWindow *window)
3525 {
3526         GtkToggleAction *toggle;
3527         ModestWindowPrivate *parent_priv;
3528         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3529
3530         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3531         gtk_toggle_action_set_active (toggle, FALSE);
3532 }
3533
3534 gboolean 
3535 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3536 {
3537         ModestMsgEditWindowPrivate *priv;
3538
3539         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3540         return priv->sent;
3541 }
3542
3543 void 
3544 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3545                                  gboolean sent)
3546 {
3547         ModestMsgEditWindowPrivate *priv;
3548
3549         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3550         priv->sent = sent;
3551 }
3552
3553
3554 void            
3555 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3556                                   TnyMsg *draft)
3557 {
3558         ModestMsgEditWindowPrivate *priv;
3559         TnyHeader *header = NULL;
3560
3561         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3562         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3563
3564         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3565         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3566
3567         if (priv->draft_msg != NULL) {
3568                 g_object_unref (priv->draft_msg);
3569         }
3570
3571         if (draft != NULL) {
3572                 g_object_ref (draft);
3573                 header = tny_msg_get_header (draft);
3574                 if (priv->msg_uid) {
3575                         g_free (priv->msg_uid);
3576                         priv->msg_uid = NULL;
3577                 }
3578                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3579                 if (GTK_WIDGET_REALIZED (window))
3580                         modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3581         }
3582
3583         priv->draft_msg = draft;
3584 }
3585
3586 static void  
3587 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3588                        GtkTextIter *start, GtkTextIter *end,
3589                        gpointer userdata)
3590 {
3591         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3592         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3593         gchar *tag_name;
3594
3595         if (tag == NULL+13) return;
3596         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3597         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3598                 replace_with_images (window, priv->images);
3599         }
3600 }
3601
3602 void                    
3603 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3604                                  TnyMimePart *part)
3605 {
3606         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3607
3608         g_return_if_fail (TNY_IS_MIME_PART (part));
3609         tny_list_prepend (priv->attachments, (GObject *) part);
3610         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3611         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3612         gtk_widget_show_all (priv->attachments_caption);
3613         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3614 }
3615
3616 const gchar*    
3617 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3618 {
3619         ModestMsgEditWindowPrivate *priv;
3620
3621         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3622         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3623
3624         return priv->msg_uid;
3625 }
3626
3627 GtkWidget *
3628 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3629                                          ModestMsgEditWindowWidgetType widget_type)
3630 {
3631         ModestMsgEditWindowPrivate *priv;
3632
3633         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3634         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3635
3636         switch (widget_type) {
3637         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3638                 return priv->msg_body;
3639                 break;
3640         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3641                 return priv->to_field;
3642                 break;
3643         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3644                 return priv->cc_field;
3645                 break;
3646         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3647                 return priv->bcc_field;
3648                 break;
3649         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3650                 return priv->subject_field;
3651                 break;
3652         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3653                 return priv->attachments_view;
3654                 break;
3655         default:
3656                 return NULL;
3657         }
3658 }
3659
3660 static void 
3661 remove_tags (WPTextBuffer *buffer)
3662 {
3663         GtkTextIter start, end;
3664
3665         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3666         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3667
3668         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3669 }
3670
3671 static void
3672 on_account_removed (TnyAccountStore *account_store, 
3673                     TnyAccount *account,
3674                     gpointer user_data)
3675 {
3676         /* Do nothing if it's a store account, because we use the
3677            transport to send the messages */
3678         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3679                 const gchar *parent_acc = NULL;
3680                 const gchar *our_acc = NULL;
3681
3682                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3683                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3684                 /* Close this window if I'm showing a message of the removed account */
3685                 if (strcmp (parent_acc, our_acc) == 0)
3686                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3687         }
3688 }
3689
3690 static gboolean
3691 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3692 {
3693         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3694
3695         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3696         return FALSE;
3697
3698 }
3699
3700 static void
3701 set_zoom_do_nothing (ModestWindow *window,
3702                                  gdouble zoom)
3703 {
3704 }
3705
3706 static gdouble
3707 get_zoom_do_nothing (ModestWindow *window)
3708 {
3709         return 1.0;
3710 }
3711