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