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