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