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