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