* Fixes NB#88016, set details dialog as modal. Backported from trunk
[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         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2881                                      GTK_WINDOW (dialog));
2882         gtk_widget_show_all (dialog);
2883         priv->font_dialog = dialog;
2884         response = gtk_dialog_run (GTK_DIALOG (dialog));
2885         priv->font_dialog = NULL;
2886         if (response == GTK_RESPONSE_OK) {
2887
2888                 g_object_get( dialog,
2889                               "bold", &bold,
2890                               "bold-set", &bold_set,
2891                               "underline", &underline,
2892                               "underline-set", &underline_set,
2893                               "italic", &italic,
2894                               "italic-set", &italic_set,
2895                               "strikethrough", &strikethrough,
2896                               "strikethrough-set", &strikethrough_set,
2897                               "color", &color,
2898                               "color-set", &color_set,
2899                               "size", &font_size,
2900                               "size-set", &font_size_set,
2901                               "family", &font_name,
2902                               "family-set", &font_set,
2903                               "position", &position,
2904                               "position-set", &position_set,
2905                               NULL );
2906                 
2907         }       
2908
2909         if (response == GTK_RESPONSE_OK) {
2910                 memset(&fmt, 0, sizeof(fmt));
2911                 if (bold_set) {
2912                         fmt.bold = bold;
2913                         fmt.cs.bold = TRUE;
2914                 }
2915                 if (italic_set) {
2916                         fmt.italic = italic;
2917                         fmt.cs.italic = TRUE;
2918                 }
2919                 if (underline_set) {
2920                         fmt.underline = underline;
2921                         fmt.cs.underline = TRUE;
2922                 }
2923                 if (strikethrough_set) {
2924                         fmt.strikethrough = strikethrough;
2925                         fmt.cs.strikethrough = TRUE;
2926                 }
2927                 if (position_set) {
2928                         fmt.text_position =
2929                                 ( position == 0 )
2930                                 ? TEXT_POSITION_NORMAL
2931                                 : ( ( position == 1 )
2932                                     ? TEXT_POSITION_SUPERSCRIPT
2933                                     : TEXT_POSITION_SUBSCRIPT );
2934                         fmt.cs.text_position = TRUE;
2935                         fmt.font_size = oldfmt.font_size;
2936                 }
2937                 if (color_set) {
2938                         fmt.color = *color;
2939                         fmt.cs.color = TRUE;
2940                 }
2941                 if (font_set) {
2942                         fmt.font = wp_get_font_index(font_name,
2943                                                      DEFAULT_FONT);
2944                         fmt.cs.font = TRUE;
2945                 }
2946                 g_free(font_name);
2947                 if (font_size_set) {
2948                         fmt.cs.font_size = TRUE;
2949                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2950                 }
2951                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2952                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2953         }
2954         gtk_widget_destroy (dialog);
2955         
2956         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2957 }
2958
2959 void
2960 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2961 {
2962         ModestMsgEditWindowPrivate *priv;
2963
2964         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2965         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2966         
2967         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2968
2969         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2970         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2971
2972 }
2973
2974 void
2975 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2976 {
2977         ModestMsgEditWindowPrivate *priv;
2978
2979         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2980         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2981         
2982         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2983
2984         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2985         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2986
2987 }
2988
2989 static void  
2990 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2991 {
2992         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2993
2994         priv->can_undo = can_undo;
2995 }
2996
2997 static void  
2998 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2999 {
3000         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3001
3002         priv->can_redo = can_redo;
3003 }
3004
3005 gboolean            
3006 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3007 {
3008         ModestMsgEditWindowPrivate *priv;
3009         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3010         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3011
3012         return priv->can_undo;
3013 }
3014
3015 gboolean            
3016 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3017 {
3018         ModestMsgEditWindowPrivate *priv;
3019         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3020         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3021
3022         return priv->can_redo;
3023 }
3024
3025
3026 static void
3027 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3028 {
3029         GtkTextIter iter;
3030         GtkTextIter match_start, match_end;
3031
3032         if (image_id == NULL)
3033                 return;
3034
3035         gtk_text_buffer_get_start_iter (buffer, &iter);
3036
3037         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3038                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3039                 GSList *node;
3040                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3041                         GtkTextTag *tag = (GtkTextTag *) node->data;
3042                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3043                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3044                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3045                                         gint offset;
3046                                         offset = gtk_text_iter_get_offset (&match_start);
3047                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3048                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3049                                 }
3050                         }
3051                 }
3052                 gtk_text_iter_forward_char (&iter);
3053         }
3054 }
3055
3056 gboolean
3057 message_is_empty (ModestMsgEditWindow *window)
3058 {
3059         ModestMsgEditWindowPrivate *priv = NULL;
3060
3061         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3062         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3063
3064         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3065          * so we can ignore markup.
3066          */
3067         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3068         gint count = 0;
3069         if (buf)
3070                 count = gtk_text_buffer_get_char_count (buf);
3071
3072         return count == 0;
3073 }
3074
3075 static gboolean
3076 msg_body_focus (GtkWidget *focus,
3077                 GdkEventFocus *event,
3078                 gpointer userdata)
3079 {
3080         
3081         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3082         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3083         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3084         return FALSE;
3085 }
3086
3087 static void
3088 recpt_field_changed (GtkTextBuffer *buffer,
3089                   ModestMsgEditWindow *editor)
3090 {
3091         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3092         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3093 }
3094
3095 static void
3096 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3097 {
3098         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3099         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3100 }
3101
3102 void
3103 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3104                                      gboolean modified)
3105 {
3106         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3107         GtkTextBuffer *buffer;
3108
3109         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3110         gtk_text_buffer_set_modified (buffer, modified);
3111         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3112         gtk_text_buffer_set_modified (buffer, modified);
3113         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3114         gtk_text_buffer_set_modified (buffer, modified);
3115         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3116 }
3117
3118 gboolean
3119 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3120 {
3121         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3122         const char *account_name;
3123         GtkTextBuffer *buffer;
3124
3125         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3126         if (gtk_text_buffer_get_modified (buffer))
3127                 return TRUE;
3128         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3129         if (gtk_text_buffer_get_modified (buffer))
3130                 return TRUE;
3131         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3132         if (gtk_text_buffer_get_modified (buffer))
3133                 return TRUE;
3134         if (gtk_text_buffer_get_modified (priv->text_buffer))
3135                 return TRUE;
3136         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
3137         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3138                 return TRUE;
3139         }
3140
3141         return FALSE;
3142 }
3143
3144
3145
3146
3147 gboolean
3148 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3149 {
3150         ModestMsgEditWindowPrivate *priv = NULL;
3151         
3152         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3153         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3154
3155         /* check if there's no recipient added */
3156         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3157             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3158             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3159                 /* no recipient contents, then select contacts */
3160                 modest_msg_edit_window_open_addressbook (window, NULL);
3161                 return FALSE;
3162         }
3163
3164         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3165                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3166                 return FALSE;
3167         }
3168         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3169                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3170                 return FALSE;
3171         }
3172         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3173                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3174                 return FALSE;
3175         }
3176
3177         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3178             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3179                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3180
3181         return TRUE;
3182
3183 }
3184
3185 static void
3186 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3187                                                ModestMsgEditWindow *window)
3188 {
3189         modest_msg_edit_window_offer_attach_file (window);
3190 }
3191
3192 const gchar *
3193 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3194 {
3195         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3196
3197         return priv->clipboard_text;
3198 }
3199
3200 static void
3201 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3202                                                GdkEvent *event,
3203                                                ModestMsgEditWindow *window)
3204 {
3205         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3206         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3207         gchar *text = NULL;
3208         if (!GTK_WIDGET_VISIBLE (window))
3209                 return;
3210
3211         g_object_ref (window);
3212         text = gtk_clipboard_wait_for_text (selection_clipboard);
3213
3214         if (priv->clipboard_text != NULL) {
3215                 g_free (priv->clipboard_text);
3216         }
3217         priv->clipboard_text = text;
3218
3219         if (GTK_WIDGET_VISIBLE (window)) {
3220                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3221         }
3222         g_object_unref (window);
3223 }
3224
3225 static gboolean clipboard_owner_change_idle (gpointer userdata)
3226 {
3227         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3228         ModestMsgEditWindowPrivate *priv;
3229
3230         gdk_threads_enter ();
3231         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3232         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3233
3234         priv->clipboard_owner_idle = 0;
3235         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3236         gdk_threads_leave ();
3237
3238         return FALSE;
3239 }
3240
3241 static void
3242 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3243 {
3244         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3245         if (priv->clipboard_owner_idle == 0) {
3246                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3247         }
3248 }
3249
3250 static void 
3251 subject_field_move_cursor (GtkEntry *entry,
3252                            GtkMovementStep step,
3253                            gint a1,
3254                            gboolean a2,
3255                            gpointer window)
3256 {
3257         if (!GTK_WIDGET_VISIBLE (window))
3258                 return;
3259
3260         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3261 }
3262
3263 static void 
3264 update_window_title (ModestMsgEditWindow *window)
3265 {
3266         ModestMsgEditWindowPrivate *priv = NULL;
3267         const gchar *subject;
3268
3269         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3270         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3271         if (subject == NULL || subject[0] == '\0')
3272                 subject = _("mail_va_new_email");
3273
3274         gtk_window_set_title (GTK_WINDOW (window), subject);
3275
3276 }
3277
3278 static void  
3279 subject_field_changed (GtkEditable *editable, 
3280                        ModestMsgEditWindow *window)
3281 {
3282         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3283         update_window_title (window);
3284         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3285         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3286         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3287 }
3288
3289 static void  
3290 subject_field_insert_text (GtkEditable *editable, 
3291                            gchar *new_text,
3292                            gint new_text_length,
3293                            gint *position,
3294                            ModestMsgEditWindow *window)
3295 {
3296         GString *result = g_string_new ("");
3297         gchar *current;
3298         gint result_len = 0;
3299         const gchar *entry_text = NULL;
3300         gint old_length;
3301
3302         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3303         old_length = g_utf8_strlen (entry_text, -1);
3304
3305         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3306                 gunichar c = g_utf8_get_char_validated (current, 8);
3307                 /* Invalid unichar, stop */
3308                 if (c == -1)
3309                         break;
3310                 /* a bullet */
3311                 if (c == 0x2022)
3312                         continue;
3313                 result = g_string_append_unichar (result, c);
3314                 result_len++;
3315         }
3316
3317         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3318                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3319                 if (result_len > 0)
3320                 {
3321                         /* Prevent endless recursion */
3322                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3323                         g_signal_emit_by_name (editable, "insert-text", 
3324                                                (gpointer) result->str, (gpointer) result->len,
3325                                                (gpointer) position, (gpointer) window);
3326                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3327                 }
3328         }
3329
3330         if (result_len + old_length > 1000) {
3331                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3332                                                 dgettext("hildon-common-strings",
3333                                                          "ckdg_ib_maximum_characters_reached"));
3334         }
3335         
3336         g_string_free (result, TRUE);
3337 }
3338
3339 void
3340 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3341                                             gboolean show)
3342 {
3343         ModestMsgEditWindowPrivate *priv = NULL;
3344
3345         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3346         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3347
3348         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3349
3350         if (show) {
3351                 gtk_widget_show_all (priv->find_toolbar);
3352                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3353         } else {
3354                 gtk_widget_hide_all (priv->find_toolbar);
3355                 gtk_widget_grab_focus (priv->msg_body);
3356         }
3357     
3358 }
3359
3360 static gboolean 
3361 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3362                                           const gchar *str,
3363                                           GtkTextIter *match_start,
3364                                           GtkTextIter *match_end)
3365 {
3366         GtkTextIter end_iter;
3367         gchar *str_casefold;
3368         gint str_chars_n;
3369         gchar *range_text;
3370         gchar *range_casefold;
3371         gint offset;
3372         gint range_chars_n;
3373         gboolean result = FALSE;
3374
3375         if (str == NULL)
3376                 return TRUE;
3377         
3378         /* get end iter */
3379         end_iter = *iter;
3380         gtk_text_iter_forward_to_end (&end_iter);
3381
3382         str_casefold = g_utf8_casefold (str, -1);
3383         str_chars_n = strlen (str);
3384
3385         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3386         range_casefold = g_utf8_casefold (range_text, -1);
3387         range_chars_n = strlen (range_casefold);
3388
3389         if (range_chars_n < str_chars_n) {
3390                 g_free (str_casefold);
3391                 g_free (range_text);
3392                 g_free (range_casefold);
3393                 return FALSE;
3394         }
3395
3396         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3397                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3398                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3399                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3400                         result = TRUE;
3401                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3402                                                       match_start, match_end, NULL);
3403                         g_free (found_text);
3404                 }
3405                 g_free (range_subtext);
3406                 if (result)
3407                         break;
3408         }
3409         g_free (str_casefold);
3410         g_free (range_text);
3411         g_free (range_casefold);
3412
3413         return result;
3414 }
3415
3416
3417 static void 
3418 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3419                                             ModestMsgEditWindow *window)
3420 {
3421         gchar *current_search = NULL;
3422         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3423         gboolean result;
3424         GtkTextIter selection_start, selection_end;
3425         GtkTextIter match_start, match_end;
3426         gboolean continue_search = FALSE;
3427
3428         if (message_is_empty (window)) {
3429                 g_free (priv->last_search);
3430                 priv->last_search = NULL;
3431                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3432                 return;
3433         }
3434
3435         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3436         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3437                 g_free (current_search);
3438                 g_free (priv->last_search);
3439                 priv->last_search = NULL;
3440                 /* Information banner about empty search */
3441                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3442                 return;
3443         }
3444
3445         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3446                 continue_search = TRUE;
3447         } else {
3448                 g_free (priv->last_search);
3449                 priv->last_search = g_strdup (current_search);
3450         }
3451
3452         if (continue_search) {
3453                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3454                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3455                                                                    &match_start, &match_end);
3456                 if (!result)
3457                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3458         } else {
3459                 GtkTextIter buffer_start;
3460                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3461                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3462                                                                    &match_start, &match_end);
3463                 if (!result)
3464                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3465         }
3466
3467         /* Mark as selected the string found in search */
3468         if (result) {
3469                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3470                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3471                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3472         } else {
3473                 g_free (priv->last_search);
3474                 priv->last_search = NULL;
3475         }
3476         g_free (current_search);
3477 }
3478
3479 static void
3480 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3481                                            ModestMsgEditWindow *window)
3482 {
3483         GtkToggleAction *toggle;
3484         ModestWindowPrivate *parent_priv;
3485         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3486
3487         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3488         gtk_toggle_action_set_active (toggle, FALSE);
3489 }
3490
3491 gboolean 
3492 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3493 {
3494         ModestMsgEditWindowPrivate *priv;
3495
3496         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3497         return priv->sent;
3498 }
3499
3500 void 
3501 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3502                                  gboolean sent)
3503 {
3504         ModestMsgEditWindowPrivate *priv;
3505
3506         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3507         priv->sent = sent;
3508 }
3509
3510
3511 void            
3512 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3513                                   TnyMsg *draft)
3514 {
3515         ModestMsgEditWindowPrivate *priv;
3516         TnyHeader *header = NULL;
3517
3518         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3519         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3520
3521         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3522         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3523
3524         if (priv->draft_msg != NULL) {
3525                 g_object_unref (priv->draft_msg);
3526         }
3527
3528         if (draft != NULL) {
3529                 g_object_ref (draft);
3530                 header = tny_msg_get_header (draft);
3531                 if (priv->msg_uid) {
3532                         g_free (priv->msg_uid);
3533                         priv->msg_uid = NULL;
3534                 }
3535                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3536                 if (GTK_WIDGET_REALIZED (window))
3537                         modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3538         }
3539
3540         priv->draft_msg = draft;
3541 }
3542
3543 static void  
3544 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3545                        GtkTextIter *start, GtkTextIter *end,
3546                        gpointer userdata)
3547 {
3548         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3549         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3550         gchar *tag_name;
3551
3552         if (tag == NULL+13) return;
3553         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3554         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3555                 replace_with_images (window, priv->images);
3556         }
3557 }
3558
3559 void                    
3560 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3561                                  TnyMimePart *part)
3562 {
3563         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3564
3565         g_return_if_fail (TNY_IS_MIME_PART (part));
3566         tny_list_prepend (priv->attachments, (GObject *) part);
3567         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3568         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3569         gtk_widget_show_all (priv->attachments_caption);
3570         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3571 }
3572
3573 const gchar*    
3574 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3575 {
3576         ModestMsgEditWindowPrivate *priv;
3577
3578         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3579         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3580
3581         return priv->msg_uid;
3582 }
3583
3584 GtkWidget *
3585 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3586                                          ModestMsgEditWindowWidgetType widget_type)
3587 {
3588         ModestMsgEditWindowPrivate *priv;
3589
3590         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3591         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3592
3593         switch (widget_type) {
3594         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3595                 return priv->msg_body;
3596                 break;
3597         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3598                 return priv->to_field;
3599                 break;
3600         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3601                 return priv->cc_field;
3602                 break;
3603         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3604                 return priv->bcc_field;
3605                 break;
3606         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3607                 return priv->subject_field;
3608                 break;
3609         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3610                 return priv->attachments_view;
3611                 break;
3612         default:
3613                 return NULL;
3614         }
3615 }
3616
3617 static void 
3618 remove_tags (WPTextBuffer *buffer)
3619 {
3620         GtkTextIter start, end;
3621
3622         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3623         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3624
3625         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3626 }
3627
3628 static void
3629 on_account_removed (TnyAccountStore *account_store, 
3630                     TnyAccount *account,
3631                     gpointer user_data)
3632 {
3633         /* Do nothing if it's a store account, because we use the
3634            transport to send the messages */
3635         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3636                 const gchar *parent_acc = NULL;
3637                 const gchar *our_acc = NULL;
3638
3639                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3640                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3641                 /* Close this window if I'm showing a message of the removed account */
3642                 if (strcmp (parent_acc, our_acc) == 0)
3643                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3644         }
3645 }
3646
3647 static gboolean
3648 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3649 {
3650         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3651
3652         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3653         return FALSE;
3654
3655 }
3656
3657 static void
3658 set_zoom_do_nothing (ModestWindow *window,
3659                                  gdouble zoom)
3660 {
3661 }
3662
3663 static gdouble
3664 get_zoom_do_nothing (ModestWindow *window)
3665 {
3666         return 1.0;
3667 }
3668