* Fixes NB#83408, select attachment is now set as children of the edit window
[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                         TnyStream *memstream = tny_camel_mem_stream_new ();
2168                         tny_stream_write_to_stream (vfssstream, memstream);
2169                         g_object_unref (vfssstream);
2170                         result = memstream;
2171                 } else {
2172                         result = vfssstream;
2173                 }
2174         }
2175         
2176         return result;
2177 }
2178
2179 void
2180 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2181 {
2182         
2183         ModestMsgEditWindowPrivate *priv;
2184         GtkWidget *dialog = NULL;
2185         gint response = 0;
2186         GSList *uris = NULL;
2187         GSList *uri_node = NULL;
2188         
2189         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2190         
2191         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2192         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2193         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2194
2195         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2196
2197         response = gtk_dialog_run (GTK_DIALOG (dialog));
2198         switch (response) {
2199         case GTK_RESPONSE_OK:
2200                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2201                 break;
2202         default:
2203                 break;
2204         }
2205         gtk_widget_destroy (dialog);
2206
2207         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2208                 const gchar *uri;
2209                 GnomeVFSHandle *handle = NULL;
2210                 GnomeVFSResult result;
2211                 GtkTextIter position;
2212                 GtkTextMark *insert_mark;
2213
2214                 uri = (const gchar *) uri_node->data;
2215                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2216                 if (result == GNOME_VFS_OK) {
2217                         GdkPixbuf *pixbuf;
2218                         GnomeVFSFileInfo *info;
2219                         gchar *filename, *basename, *escaped_filename;
2220                         TnyMimePart *mime_part;
2221                         gchar *content_id;
2222                         const gchar *mime_type = NULL;
2223                         GnomeVFSURI *vfs_uri;
2224                         guint64 stream_size;
2225
2226                         gnome_vfs_close (handle);
2227                         vfs_uri = gnome_vfs_uri_new (uri);
2228
2229                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2230                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2231                         g_free (escaped_filename);
2232                         gnome_vfs_uri_unref (vfs_uri);
2233                         info = gnome_vfs_file_info_new ();
2234
2235                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2236                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2237                             == GNOME_VFS_OK)
2238                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2239
2240                         mime_part = tny_platform_factory_new_mime_part
2241                                 (modest_runtime_get_platform_factory ());
2242                                 
2243                         TnyStream *stream = create_stream_for_uri (uri);
2244
2245                         if (stream == NULL) {
2246
2247                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2248                                 
2249                                 g_object_unref (mime_part);
2250                                 gnome_vfs_file_info_unref (info);
2251                                 continue;
2252                         }
2253
2254                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2255                         
2256                         content_id = g_strdup_printf ("%d", priv->next_cid);
2257                         tny_mime_part_set_content_id (mime_part, content_id);
2258                         g_free (content_id);
2259                         priv->next_cid++;
2260                         
2261                         basename = g_path_get_basename (filename);
2262                         tny_mime_part_set_filename (mime_part, basename);
2263                         g_free (basename);
2264
2265                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2266                         
2267                         if (pixbuf != NULL) {
2268                                 priv->images_size += stream_size;
2269                                 priv->images_count ++;
2270                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2271                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2272                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2273                         } 
2274
2275                         tny_list_prepend (priv->images, (GObject *) mime_part);
2276                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2277                         g_free (filename);
2278                         g_object_unref (mime_part);
2279                         gnome_vfs_file_info_unref (info);
2280
2281                 }
2282         }
2283
2284
2285 }
2286
2287 void
2288 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2289 {       
2290         GtkWidget *dialog = NULL;
2291         gint response = 0;
2292         GSList *uris = NULL;
2293         GSList *uri_node;
2294         
2295         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2296         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2297         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2298         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
2299
2300         response = gtk_dialog_run (GTK_DIALOG (dialog));
2301         switch (response) {
2302         case GTK_RESPONSE_OK:
2303                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2304                 break;
2305         default:
2306                 break;
2307         }
2308         gtk_widget_destroy (dialog);
2309
2310         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2311                 const gchar *uri = (const gchar *) uri_node->data;
2312                 modest_msg_edit_window_attach_file_one (window, uri);
2313         }
2314         g_slist_foreach (uris, (GFunc) g_free, NULL);
2315         g_slist_free (uris);
2316 }
2317
2318 void
2319 modest_msg_edit_window_attach_file_one (
2320                 ModestMsgEditWindow *window,
2321                 const gchar *uri)
2322 {
2323         GnomeVFSHandle *handle = NULL;
2324         ModestMsgEditWindowPrivate *priv;
2325         GnomeVFSResult result;
2326
2327         g_return_if_fail (window);
2328         g_return_if_fail (uri);
2329                 
2330         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2331         
2332         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2333         if (result == GNOME_VFS_OK) {
2334                 TnyMimePart *mime_part;
2335                 TnyStream *stream;
2336                 const gchar *mime_type = NULL;
2337                 gchar *basename;
2338                 gchar *escaped_filename;
2339                 gchar *filename;
2340                 gchar *content_id;
2341                 GnomeVFSFileInfo *info;
2342                 GnomeVFSURI *vfs_uri;
2343
2344                 gnome_vfs_close (handle);
2345                 vfs_uri = gnome_vfs_uri_new (uri);
2346                 
2347
2348                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2349                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2350                 g_free (escaped_filename);
2351                 gnome_vfs_uri_unref (vfs_uri);
2352
2353                 info = gnome_vfs_file_info_new ();
2354                 
2355                 if (gnome_vfs_get_file_info (uri, 
2356                                              info, 
2357                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2358                     == GNOME_VFS_OK)
2359                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2360                 mime_part = tny_platform_factory_new_mime_part
2361                         (modest_runtime_get_platform_factory ());
2362                 stream = create_stream_for_uri (uri);
2363                 
2364                 if (stream == NULL) {
2365
2366                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2367
2368                         g_object_unref (mime_part);
2369                         gnome_vfs_file_info_unref (info);
2370                         return;
2371                 }
2372
2373                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2374                 g_object_unref (stream);
2375                 
2376                 content_id = g_strdup_printf ("%d", priv->next_cid);
2377                 tny_mime_part_set_content_id (mime_part, content_id);
2378                 g_free (content_id);
2379                 priv->next_cid++;
2380                 
2381                 basename = g_path_get_basename (filename);
2382                 tny_mime_part_set_filename (mime_part, basename);
2383                 g_free (basename);
2384                 
2385                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2386                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2387                                                         mime_part,
2388                                                         info->size == 0, info->size);
2389                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2390                 gtk_widget_show_all (priv->attachments_caption);
2391                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2392                 g_free (filename);
2393                 g_object_unref (mime_part);
2394                 gnome_vfs_file_info_unref (info);
2395         }
2396 }
2397
2398 void
2399 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2400                                            TnyList *att_list)
2401 {
2402         ModestMsgEditWindowPrivate *priv;
2403         TnyIterator *iter;
2404
2405         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2406         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2407
2408         if (att_list == NULL) {
2409                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2410         } else {
2411                 g_object_ref (att_list);
2412         }
2413
2414         if (tny_list_get_length (att_list) == 0) {
2415                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2416         } else {
2417                 GtkWidget *confirmation_dialog = NULL;
2418                 gboolean dialog_response;
2419                 gchar *message = NULL;
2420                 gchar *filename = NULL;
2421
2422                 if (tny_list_get_length (att_list) == 1) {
2423                         TnyMimePart *part;
2424                         iter = tny_list_create_iterator (att_list);
2425                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2426                         g_object_unref (iter);
2427                         if (TNY_IS_MSG (part)) {
2428                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2429                                 if (header) {
2430                                         filename = tny_header_dup_subject (header);
2431                                         g_object_unref (header);
2432                                 }
2433                                 if (filename == NULL) {
2434                                         filename = g_strdup (_("mail_va_no_subject"));
2435                                 }
2436                         } else {
2437                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2438                         }
2439                         g_object_unref (part);
2440                 } else {
2441                         filename = g_strdup ("");
2442                 }
2443                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2444                                                     tny_list_get_length (att_list)), filename);
2445                 g_free (filename);
2446                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2447                 g_free (message);
2448                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2449                 gtk_widget_destroy (confirmation_dialog);
2450                 if (!dialog_response) {
2451                         g_object_unref (att_list);
2452                         return;
2453                 }
2454                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2455                 
2456                 for (iter = tny_list_create_iterator (att_list);
2457                      !tny_iterator_is_done (iter);
2458                      tny_iterator_next (iter)) {
2459                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2460                         const gchar *att_id;
2461                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2462
2463                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2464                                                                    mime_part);
2465                         if (tny_list_get_length (priv->attachments) == 0)
2466                                 gtk_widget_hide (priv->attachments_caption);
2467                         att_id = tny_mime_part_get_content_id (mime_part);
2468                         if (att_id != NULL)
2469                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2470                                                                  att_id);
2471                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2472                         g_object_unref (mime_part);
2473                 }
2474                 g_object_unref (iter);
2475         }
2476
2477         g_object_unref (att_list);
2478
2479         /* if the last attachment has been removed, focus the Subject: field */
2480         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2481                 gtk_widget_grab_focus (priv->subject_field);
2482 }
2483
2484 static void
2485 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2486                                             gpointer userdata)
2487 {
2488         ModestMsgEditWindowPrivate *priv;
2489         GdkColor *new_color;
2490         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2491         
2492 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2493         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2494 #else 
2495         GdkColor col;
2496         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2497         new_color = &col;
2498 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2499
2500         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2501         
2502         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2503
2504 }
2505
2506 static void
2507 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2508                                     gpointer userdata)
2509 {
2510         ModestMsgEditWindowPrivate *priv;
2511         gint new_size_index;
2512         ModestMsgEditWindow *window;
2513         GtkWidget *label;
2514         
2515         window = MODEST_MSG_EDIT_WINDOW (userdata);
2516         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2517         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2518
2519         if (gtk_check_menu_item_get_active (menu_item)) {
2520                 gchar *markup;
2521                 WPTextBufferFormat format;
2522
2523                 memset (&format, 0, sizeof (format));
2524                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2525
2526                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2527                 
2528                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2529                 format.cs.font_size = TRUE;
2530                 format.cs.text_position = TRUE;
2531                 format.cs.font = TRUE;
2532                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2533 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2534
2535                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2536                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2537                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2538                 
2539                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2540                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2541                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2542                 g_free (markup);
2543         }
2544 }
2545
2546 static void
2547 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2548                                     gpointer userdata)
2549 {
2550         ModestMsgEditWindowPrivate *priv;
2551         gint new_font_index;
2552         ModestMsgEditWindow *window;
2553         GtkWidget *label;
2554         
2555         window = MODEST_MSG_EDIT_WINDOW (userdata);
2556         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2557         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2558
2559         if (gtk_check_menu_item_get_active (menu_item)) {
2560                 gchar *markup;
2561
2562                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2563                 
2564                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2565
2566                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2567                                                    GINT_TO_POINTER(new_font_index)))
2568                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2569                 
2570                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2571                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2572                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2573                 g_free (markup);
2574         }
2575 }
2576
2577 static gboolean
2578 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2579 {
2580         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2581                 ModestWindowPrivate *parent_priv;
2582                 ModestWindowMgr *mgr;
2583                 gboolean is_fullscreen;
2584                 GtkAction *fs_toggle_action;
2585                 gboolean active;
2586
2587                 mgr = modest_runtime_get_window_mgr ();
2588                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2589
2590                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2591                 
2592                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2593                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2594                 if (is_fullscreen != active)
2595                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2596         }
2597
2598         return FALSE;
2599
2600 }
2601
2602 void
2603 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2604                                 gboolean show)
2605 {
2606         ModestMsgEditWindowPrivate *priv = NULL;
2607         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2608
2609         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2610         if (!priv->update_caption_visibility)
2611                 return;
2612
2613         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2614         if (show)
2615                 gtk_widget_show (priv->cc_caption);
2616         else
2617                 gtk_widget_hide (priv->cc_caption);
2618
2619         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2620 }
2621
2622 void
2623 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2624                                  gboolean show)
2625 {
2626         ModestMsgEditWindowPrivate *priv = NULL;
2627         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2628
2629         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2630         if (!priv->update_caption_visibility)
2631                 return;
2632
2633         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2634         if (show)
2635                 gtk_widget_show (priv->bcc_caption);
2636         else
2637                 gtk_widget_hide (priv->bcc_caption);
2638
2639         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2640 }
2641
2642 static void
2643 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2644                                          ModestRecptEditor *editor)
2645 {
2646         ModestMsgEditWindowPrivate *priv;
2647
2648         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2649         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2650         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2651
2652         if (editor == NULL) {
2653                 GtkWidget *view_focus;
2654                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2655
2656                 /* This code should be kept in sync with ModestRecptEditor. The
2657                    textview inside the recpt editor is the one that really gets the
2658                    focus. As it's inside a scrolled window, and this one inside the
2659                    hbox recpt editor inherits from, we'll need to go up in the 
2660                    hierarchy to know if the text view is part of the recpt editor
2661                    or if it's a different text entry */
2662
2663                 if (gtk_widget_get_parent (view_focus)) {
2664                         GtkWidget *first_parent;
2665
2666                         first_parent = gtk_widget_get_parent (view_focus);
2667                         if (gtk_widget_get_parent (first_parent) && 
2668                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2669                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2670                         }
2671                 }
2672
2673                 if (editor == NULL)
2674                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2675
2676         }
2677
2678         modest_address_book_select_addresses (editor);
2679
2680 }
2681
2682 void
2683 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2684 {
2685         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2686
2687         modest_msg_edit_window_open_addressbook (window, NULL);
2688 }
2689
2690 static void
2691 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2692                                      gboolean show_toolbar)
2693 {
2694         ModestWindowPrivate *parent_priv;
2695         const gchar *action_name;
2696         GtkAction *action;
2697         
2698         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2699         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2700
2701         /* We can not just use the code of
2702            modest_msg_edit_window_setup_toolbar because it has a
2703            mixture of both initialization and creation code. */
2704         if (show_toolbar)
2705                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2706         else
2707                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2708
2709         /* Update also the actions (to update the toggles in the
2710            menus), we have to do it manually because some other window
2711            of the same time could have changed it (remember that the
2712            toolbar fullscreen mode is shared by all the windows of the
2713            same type */
2714         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2715                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2716         else
2717                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2718         
2719         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2720         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2721                                                             show_toolbar);
2722
2723 }
2724
2725 void
2726 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2727                                            TnyHeaderFlags priority_flags)
2728 {
2729         ModestMsgEditWindowPrivate *priv;
2730         ModestWindowPrivate *parent_priv;
2731
2732         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2733
2734         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2735         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2736
2737         if (priv->priority_flags != priority_flags) {
2738                 GtkAction *priority_action = NULL;
2739
2740                 priv->priority_flags = priority_flags;
2741
2742                 switch (priority_flags) {
2743                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2744                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2745                         gtk_widget_show (priv->priority_icon);
2746                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2747                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2748                         break;
2749                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2750                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2751                         gtk_widget_show (priv->priority_icon);
2752                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2753                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2754                         break;
2755                 default:
2756                         gtk_widget_hide (priv->priority_icon);
2757                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2758                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2759                         break;
2760                 }
2761                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2762                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2763         }
2764 }
2765
2766 void
2767 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2768                                         gint file_format)
2769 {
2770         ModestMsgEditWindowPrivate *priv;
2771         ModestWindowPrivate *parent_priv;
2772         gint current_format;
2773
2774         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2775
2776         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2777         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2778
2779         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2780                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2781
2782         if (current_format != file_format) {
2783                 switch (file_format) {
2784                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2785                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2786                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2787                         break;
2788                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2789                 {
2790                         GtkWidget *dialog;
2791                         gint response;
2792                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2793                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2794                         gtk_widget_destroy (dialog);
2795                         if (response == GTK_RESPONSE_OK) {
2796                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2797                         } else {
2798                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2799                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2800                         }
2801                 }
2802                         break;
2803                 }
2804                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2805                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2806         }
2807 }
2808
2809 void
2810 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2811 {
2812         GtkWidget *dialog;
2813         ModestMsgEditWindowPrivate *priv;
2814         WPTextBufferFormat oldfmt, fmt;
2815         gint old_position = 0;
2816         gint response = 0;
2817         gint position = 0;
2818         gint font_size;
2819         GdkColor *color = NULL;
2820         gboolean bold, bold_set, italic, italic_set;
2821         gboolean underline, underline_set;
2822         gboolean strikethrough, strikethrough_set;
2823         gboolean position_set;
2824         gboolean font_size_set, font_set, color_set;
2825         gchar *font_name;
2826
2827         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2828         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2829         
2830         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2831         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2832                                      GTK_WINDOW(dialog));
2833
2834         /* First we get the currently selected font information */
2835         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2836
2837         switch (oldfmt.text_position) {
2838         case TEXT_POSITION_NORMAL:
2839                 old_position = 0;
2840                 break;
2841         case TEXT_POSITION_SUPERSCRIPT:
2842                 old_position = 1;
2843                 break;
2844         default:
2845                 old_position = -1;
2846                 break;
2847         }
2848
2849         g_object_set (G_OBJECT (dialog),
2850                       "bold", oldfmt.bold != FALSE,
2851                       "bold-set", !oldfmt.cs.bold,
2852                       "underline", oldfmt.underline != FALSE,
2853                       "underline-set", !oldfmt.cs.underline,
2854                       "italic", oldfmt.italic != FALSE,
2855                       "italic-set", !oldfmt.cs.italic,
2856                       "strikethrough", oldfmt.strikethrough != FALSE,
2857                       "strikethrough-set", !oldfmt.cs.strikethrough,
2858                       "color", &oldfmt.color,
2859                       "color-set", !oldfmt.cs.color,
2860                       "size", wp_font_size[oldfmt.font_size],
2861                       "size-set", !oldfmt.cs.font_size,
2862                       "position", old_position,
2863                       "position-set", !oldfmt.cs.text_position,
2864                       "family", wp_get_font_name (oldfmt.font),
2865                       "family-set", !oldfmt.cs.font,
2866                       NULL);
2867
2868         gtk_widget_show_all (dialog);
2869         response = gtk_dialog_run (GTK_DIALOG (dialog));
2870         if (response == GTK_RESPONSE_OK) {
2871
2872                 g_object_get( dialog,
2873                               "bold", &bold,
2874                               "bold-set", &bold_set,
2875                               "underline", &underline,
2876                               "underline-set", &underline_set,
2877                               "italic", &italic,
2878                               "italic-set", &italic_set,
2879                               "strikethrough", &strikethrough,
2880                               "strikethrough-set", &strikethrough_set,
2881                               "color", &color,
2882                               "color-set", &color_set,
2883                               "size", &font_size,
2884                               "size-set", &font_size_set,
2885                               "family", &font_name,
2886                               "family-set", &font_set,
2887                               "position", &position,
2888                               "position-set", &position_set,
2889                               NULL );
2890                 
2891         }       
2892
2893         if (response == GTK_RESPONSE_OK) {
2894                 memset(&fmt, 0, sizeof(fmt));
2895                 if (bold_set) {
2896                         fmt.bold = bold;
2897                         fmt.cs.bold = TRUE;
2898                 }
2899                 if (italic_set) {
2900                         fmt.italic = italic;
2901                         fmt.cs.italic = TRUE;
2902                 }
2903                 if (underline_set) {
2904                         fmt.underline = underline;
2905                         fmt.cs.underline = TRUE;
2906                 }
2907                 if (strikethrough_set) {
2908                         fmt.strikethrough = strikethrough;
2909                         fmt.cs.strikethrough = TRUE;
2910                 }
2911                 if (position_set) {
2912                         fmt.text_position =
2913                                 ( position == 0 )
2914                                 ? TEXT_POSITION_NORMAL
2915                                 : ( ( position == 1 )
2916                                     ? TEXT_POSITION_SUPERSCRIPT
2917                                     : TEXT_POSITION_SUBSCRIPT );
2918                         fmt.cs.text_position = TRUE;
2919                         fmt.font_size = oldfmt.font_size;
2920                 }
2921                 if (color_set) {
2922                         fmt.color = *color;
2923                         fmt.cs.color = TRUE;
2924                 }
2925                 if (font_set) {
2926                         fmt.font = wp_get_font_index(font_name,
2927                                                      DEFAULT_FONT);
2928                         fmt.cs.font = TRUE;
2929                 }
2930                 g_free(font_name);
2931                 if (font_size_set) {
2932                         fmt.cs.font_size = TRUE;
2933                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2934                 }
2935                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2936                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2937         }
2938         gtk_widget_destroy (dialog);
2939         
2940         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2941 }
2942
2943 void
2944 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2945 {
2946         ModestMsgEditWindowPrivate *priv;
2947
2948         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2949         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2950         
2951         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2952
2953         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2954         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2955
2956 }
2957
2958 void
2959 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2960 {
2961         ModestMsgEditWindowPrivate *priv;
2962
2963         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2964         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2965         
2966         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2967
2968         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2969         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2970
2971 }
2972
2973 static void  
2974 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2975 {
2976         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2977
2978         priv->can_undo = can_undo;
2979 }
2980
2981 static void  
2982 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2983 {
2984         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2985
2986         priv->can_redo = can_redo;
2987 }
2988
2989 gboolean            
2990 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2991 {
2992         ModestMsgEditWindowPrivate *priv;
2993         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2994         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2995
2996         return priv->can_undo;
2997 }
2998
2999 gboolean            
3000 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3001 {
3002         ModestMsgEditWindowPrivate *priv;
3003         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3004         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3005
3006         return priv->can_redo;
3007 }
3008
3009
3010 static void
3011 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3012 {
3013         GtkTextIter iter;
3014         GtkTextIter match_start, match_end;
3015
3016         if (image_id == NULL)
3017                 return;
3018
3019         gtk_text_buffer_get_start_iter (buffer, &iter);
3020
3021         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3022                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3023                 GSList *node;
3024                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3025                         GtkTextTag *tag = (GtkTextTag *) node->data;
3026                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3027                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3028                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3029                                         gint offset;
3030                                         offset = gtk_text_iter_get_offset (&match_start);
3031                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3032                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3033                                 }
3034                         }
3035                 }
3036                 gtk_text_iter_forward_char (&iter);
3037         }
3038 }
3039
3040 gboolean
3041 message_is_empty (ModestMsgEditWindow *window)
3042 {
3043         ModestMsgEditWindowPrivate *priv = NULL;
3044
3045         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3046         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3047
3048         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3049          * so we can ignore markup.
3050          */
3051         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3052         gint count = 0;
3053         if (buf)
3054                 count = gtk_text_buffer_get_char_count (buf);
3055
3056         return count == 0;
3057 }
3058
3059 static gboolean
3060 msg_body_focus (GtkWidget *focus,
3061                 GdkEventFocus *event,
3062                 gpointer userdata)
3063 {
3064         
3065         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3066         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3067         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3068         return FALSE;
3069 }
3070
3071 static void
3072 recpt_field_changed (GtkTextBuffer *buffer,
3073                   ModestMsgEditWindow *editor)
3074 {
3075         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3076         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3077 }
3078
3079 static void
3080 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3081 {
3082         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3083         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3084 }
3085
3086 void
3087 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3088                                      gboolean modified)
3089 {
3090         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3091         GtkTextBuffer *buffer;
3092
3093         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3094         gtk_text_buffer_set_modified (buffer, modified);
3095         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3096         gtk_text_buffer_set_modified (buffer, modified);
3097         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3098         gtk_text_buffer_set_modified (buffer, modified);
3099         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3100 }
3101
3102 gboolean
3103 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3104 {
3105         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3106         const char *account_name;
3107         GtkTextBuffer *buffer;
3108
3109         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3110         if (gtk_text_buffer_get_modified (buffer))
3111                 return TRUE;
3112         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3113         if (gtk_text_buffer_get_modified (buffer))
3114                 return TRUE;
3115         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3116         if (gtk_text_buffer_get_modified (buffer))
3117                 return TRUE;
3118         if (gtk_text_buffer_get_modified (priv->text_buffer))
3119                 return TRUE;
3120         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
3121         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3122                 return TRUE;
3123         }
3124
3125         return FALSE;
3126 }
3127
3128
3129
3130
3131 gboolean
3132 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3133 {
3134         ModestMsgEditWindowPrivate *priv = NULL;
3135         
3136         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3137         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3138
3139         /* check if there's no recipient added */
3140         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3141             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3142             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3143                 /* no recipient contents, then select contacts */
3144                 modest_msg_edit_window_open_addressbook (window, NULL);
3145                 return FALSE;
3146         }
3147
3148         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3149                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3150                 return FALSE;
3151         }
3152         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3153                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3154                 return FALSE;
3155         }
3156         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3157                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3158                 return FALSE;
3159         }
3160
3161         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3162             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3163                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3164
3165         return TRUE;
3166
3167 }
3168
3169 static void
3170 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3171                                                ModestMsgEditWindow *window)
3172 {
3173         modest_msg_edit_window_offer_attach_file (window);
3174 }
3175
3176 const gchar *
3177 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3178 {
3179         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3180
3181         return priv->clipboard_text;
3182 }
3183
3184 static void
3185 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3186                                                GdkEvent *event,
3187                                                ModestMsgEditWindow *window)
3188 {
3189         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3190         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3191         gchar *text = NULL;
3192         if (!GTK_WIDGET_VISIBLE (window))
3193                 return;
3194
3195         g_object_ref (window);
3196         text = gtk_clipboard_wait_for_text (selection_clipboard);
3197
3198         if (priv->clipboard_text != NULL) {
3199                 g_free (priv->clipboard_text);
3200         }
3201         priv->clipboard_text = text;
3202
3203         if (GTK_WIDGET_VISIBLE (window)) {
3204                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3205         }
3206         g_object_unref (window);
3207 }
3208
3209 static gboolean clipboard_owner_change_idle (gpointer userdata)
3210 {
3211         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3212         ModestMsgEditWindowPrivate *priv;
3213
3214         gdk_threads_enter ();
3215         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3216         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3217
3218         priv->clipboard_owner_idle = 0;
3219         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3220         gdk_threads_leave ();
3221
3222         return FALSE;
3223 }
3224
3225 static void
3226 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3227 {
3228         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3229         if (priv->clipboard_owner_idle == 0) {
3230                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3231         }
3232 }
3233
3234 static void 
3235 subject_field_move_cursor (GtkEntry *entry,
3236                            GtkMovementStep step,
3237                            gint a1,
3238                            gboolean a2,
3239                            gpointer window)
3240 {
3241         if (!GTK_WIDGET_VISIBLE (window))
3242                 return;
3243
3244         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3245 }
3246
3247 static void 
3248 update_window_title (ModestMsgEditWindow *window)
3249 {
3250         ModestMsgEditWindowPrivate *priv = NULL;
3251         const gchar *subject;
3252
3253         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3254         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3255         if (subject == NULL || subject[0] == '\0')
3256                 subject = _("mail_va_new_email");
3257
3258         gtk_window_set_title (GTK_WINDOW (window), subject);
3259
3260 }
3261
3262 static void  
3263 subject_field_changed (GtkEditable *editable, 
3264                        ModestMsgEditWindow *window)
3265 {
3266         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3267         update_window_title (window);
3268         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3269         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3270         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3271 }
3272
3273 static void  
3274 subject_field_insert_text (GtkEditable *editable, 
3275                            gchar *new_text,
3276                            gint new_text_length,
3277                            gint *position,
3278                            ModestMsgEditWindow *window)
3279 {
3280         GString *result = g_string_new ("");
3281         gchar *current;
3282         gint result_len = 0;
3283         const gchar *entry_text = NULL;
3284         gint old_length;
3285
3286         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3287         old_length = g_utf8_strlen (entry_text, -1);
3288
3289         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3290                 gunichar c = g_utf8_get_char_validated (current, 8);
3291                 /* Invalid unichar, stop */
3292                 if (c == -1)
3293                         break;
3294                 /* a bullet */
3295                 if (c == 0x2022)
3296                         continue;
3297                 result = g_string_append_unichar (result, c);
3298                 result_len++;
3299         }
3300
3301         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3302                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3303                 if (result_len > 0)
3304                 {
3305                         /* Prevent endless recursion */
3306                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3307                         g_signal_emit_by_name (editable, "insert-text", 
3308                                                (gpointer) result->str, (gpointer) result->len,
3309                                                (gpointer) position, (gpointer) window);
3310                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3311                 }
3312         }
3313
3314         if (result_len + old_length > 1000) {
3315                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3316                                                 dgettext("hildon-common-strings",
3317                                                          "ckdg_ib_maximum_characters_reached"));
3318         }
3319         
3320         g_string_free (result, TRUE);
3321 }
3322
3323 static void  
3324 text_buffer_insert_text (GtkTextBuffer *buffer, 
3325                          GtkTextIter *iter,
3326                          gchar *new_text,
3327                          gint new_text_length,
3328                          ModestMsgEditWindow *window)
3329 {
3330         GString *result = g_string_new ("");
3331         gchar *current;
3332         gint result_len = 0;
3333         gboolean changed = FALSE;
3334
3335         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3336                 gunichar c = g_utf8_get_char_validated (current, 8);
3337                 /* Invalid unichar, stop */
3338                 if (c == -1)
3339                         break;
3340                 /* a bullet */
3341                 switch (c) {
3342                 case 0x2022:
3343                         result = g_string_append_c (result, ' ');
3344                         changed = TRUE;
3345                         break;
3346                 default:
3347                         result = g_string_append_unichar (result, c);
3348                 }
3349                 result_len++;
3350         }
3351
3352         if (changed) {
3353                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3354                 g_signal_handlers_block_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3355                 g_signal_emit_by_name (buffer, "insert-text", 
3356                                        (gpointer) iter,
3357                                        (gpointer) result->str, (gpointer) result->len,
3358                                        (gpointer) window);
3359                 g_signal_handlers_unblock_by_func(G_OBJECT(buffer), G_CALLBACK(text_buffer_insert_text), window);
3360         }
3361
3362         g_string_free (result, TRUE);
3363 }
3364
3365 void
3366 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3367                                             gboolean show)
3368 {
3369         ModestMsgEditWindowPrivate *priv = NULL;
3370
3371         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3372         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3373
3374         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3375
3376         if (show) {
3377                 gtk_widget_show_all (priv->find_toolbar);
3378                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3379         } else {
3380                 gtk_widget_hide_all (priv->find_toolbar);
3381                 gtk_widget_grab_focus (priv->msg_body);
3382         }
3383     
3384 }
3385
3386 static gboolean 
3387 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3388                                           const gchar *str,
3389                                           GtkTextIter *match_start,
3390                                           GtkTextIter *match_end)
3391 {
3392         GtkTextIter end_iter;
3393         gchar *str_casefold;
3394         gint str_chars_n;
3395         gchar *range_text;
3396         gchar *range_casefold;
3397         gint offset;
3398         gint range_chars_n;
3399         gboolean result = FALSE;
3400
3401         if (str == NULL)
3402                 return TRUE;
3403         
3404         /* get end iter */
3405         end_iter = *iter;
3406         gtk_text_iter_forward_to_end (&end_iter);
3407
3408         str_casefold = g_utf8_casefold (str, -1);
3409         str_chars_n = strlen (str);
3410
3411         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3412         range_casefold = g_utf8_casefold (range_text, -1);
3413         range_chars_n = strlen (range_casefold);
3414
3415         if (range_chars_n < str_chars_n) {
3416                 g_free (str_casefold);
3417                 g_free (range_text);
3418                 g_free (range_casefold);
3419                 return FALSE;
3420         }
3421
3422         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3423                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3424                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3425                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3426                         result = TRUE;
3427                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3428                                                       match_start, match_end, NULL);
3429                         g_free (found_text);
3430                 }
3431                 g_free (range_subtext);
3432                 if (result)
3433                         break;
3434         }
3435         g_free (str_casefold);
3436         g_free (range_text);
3437         g_free (range_casefold);
3438
3439         return result;
3440 }
3441
3442
3443 static void 
3444 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3445                                             ModestMsgEditWindow *window)
3446 {
3447         gchar *current_search = NULL;
3448         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3449         gboolean result;
3450         GtkTextIter selection_start, selection_end;
3451         GtkTextIter match_start, match_end;
3452         gboolean continue_search = FALSE;
3453
3454         if (message_is_empty (window)) {
3455                 g_free (priv->last_search);
3456                 priv->last_search = NULL;
3457                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3458                 return;
3459         }
3460
3461         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3462         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3463                 g_free (current_search);
3464                 g_free (priv->last_search);
3465                 priv->last_search = NULL;
3466                 /* Information banner about empty search */
3467                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3468                 return;
3469         }
3470
3471         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3472                 continue_search = TRUE;
3473         } else {
3474                 g_free (priv->last_search);
3475                 priv->last_search = g_strdup (current_search);
3476         }
3477
3478         if (continue_search) {
3479                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3480                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3481                                                                    &match_start, &match_end);
3482                 if (!result)
3483                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3484         } else {
3485                 GtkTextIter buffer_start;
3486                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3487                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3488                                                                    &match_start, &match_end);
3489                 if (!result)
3490                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3491         }
3492
3493         /* Mark as selected the string found in search */
3494         if (result) {
3495                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3496                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3497                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3498         } else {
3499                 g_free (priv->last_search);
3500                 priv->last_search = NULL;
3501         }
3502         g_free (current_search);
3503 }
3504
3505 static void
3506 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3507                                            ModestMsgEditWindow *window)
3508 {
3509         GtkToggleAction *toggle;
3510         ModestWindowPrivate *parent_priv;
3511         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3512
3513         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3514         gtk_toggle_action_set_active (toggle, FALSE);
3515 }
3516
3517 gboolean 
3518 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3519 {
3520         ModestMsgEditWindowPrivate *priv;
3521
3522         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3523         return priv->sent;
3524 }
3525
3526 void 
3527 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3528                                  gboolean sent)
3529 {
3530         ModestMsgEditWindowPrivate *priv;
3531
3532         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3533         priv->sent = sent;
3534 }
3535
3536
3537 void            
3538 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3539                                   TnyMsg *draft)
3540 {
3541         ModestMsgEditWindowPrivate *priv;
3542         TnyHeader *header = NULL;
3543
3544         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3545         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3546
3547         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3548         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3549
3550         if (priv->draft_msg != NULL) {
3551                 g_object_unref (priv->draft_msg);
3552         }
3553
3554         if (draft != NULL) {
3555                 g_object_ref (draft);
3556                 header = tny_msg_get_header (draft);
3557                 if (priv->msg_uid) {
3558                         g_free (priv->msg_uid);
3559                         priv->msg_uid = NULL;
3560                 }
3561                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3562                 if (GTK_WIDGET_REALIZED (window))
3563                         modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3564         }
3565
3566         priv->draft_msg = draft;
3567 }
3568
3569 static void  
3570 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3571                        GtkTextIter *start, GtkTextIter *end,
3572                        gpointer userdata)
3573 {
3574         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3575         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3576         gchar *tag_name;
3577
3578         if (tag == NULL+13) return;
3579         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3580         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3581                 replace_with_images (window, priv->images);
3582         }
3583 }
3584
3585 void                    
3586 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3587                                  TnyMimePart *part)
3588 {
3589         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3590
3591         g_return_if_fail (TNY_IS_MIME_PART (part));
3592         tny_list_prepend (priv->attachments, (GObject *) part);
3593         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3594         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3595         gtk_widget_show_all (priv->attachments_caption);
3596         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3597 }
3598
3599 const gchar*    
3600 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3601 {
3602         ModestMsgEditWindowPrivate *priv;
3603
3604         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3605         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3606
3607         return priv->msg_uid;
3608 }
3609
3610 GtkWidget *
3611 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3612                                          ModestMsgEditWindowWidgetType widget_type)
3613 {
3614         ModestMsgEditWindowPrivate *priv;
3615
3616         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3617         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3618
3619         switch (widget_type) {
3620         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3621                 return priv->msg_body;
3622                 break;
3623         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3624                 return priv->to_field;
3625                 break;
3626         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3627                 return priv->cc_field;
3628                 break;
3629         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3630                 return priv->bcc_field;
3631                 break;
3632         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3633                 return priv->subject_field;
3634                 break;
3635         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3636                 return priv->attachments_view;
3637                 break;
3638         default:
3639                 return NULL;
3640         }
3641 }
3642
3643 static void 
3644 remove_tags (WPTextBuffer *buffer)
3645 {
3646         GtkTextIter start, end;
3647
3648         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3649         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3650
3651         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3652 }
3653
3654 static void
3655 on_account_removed (TnyAccountStore *account_store, 
3656                     TnyAccount *account,
3657                     gpointer user_data)
3658 {
3659         /* Do nothing if it's a store account, because we use the
3660            transport to send the messages */
3661         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3662                 const gchar *parent_acc = NULL;
3663                 const gchar *our_acc = NULL;
3664
3665                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3666                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3667                 /* Close this window if I'm showing a message of the removed account */
3668                 if (strcmp (parent_acc, our_acc) == 0)
3669                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3670         }
3671 }
3672
3673 static gboolean
3674 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3675 {
3676         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3677
3678         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3679         return FALSE;
3680
3681 }
3682
3683 static void
3684 set_zoom_do_nothing (ModestWindow *window,
3685                                  gdouble zoom)
3686 {
3687 }
3688
3689 static gdouble
3690 get_zoom_do_nothing (ModestWindow *window)
3691 {
3692         return 1.0;
3693 }
3694