* Outbox messsages are opened in edit window.
[modest] / src / maemo / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38
39 #include <config.h>
40
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
43
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
48
49 #include <modest-runtime.h>
50
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
65
66 #include "modest-hildon-includes.h"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-color-chooser.h>
69 #endif
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #ifdef MODEST_HAVE_HILDON0_WIDGETS
72 #include <libgnomevfs/gnome-vfs-mime-utils.h>
73 #else
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #endif
76 #include "modest-maemo-utils.h"
77
78
79 #define DEFAULT_FONT_SIZE 3
80 #define DEFAULT_FONT 2
81 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
82 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
83 #define DEFAULT_MAIN_VBOX_SPACING 6
84 #define SUBJECT_MAX_LENGTH 1000
85 #define IMAGE_MAX_WIDTH 608
86 #define DEFAULT_FONT_SCALE 1.5
87
88 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
89 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
90 static void  modest_msg_edit_window_finalize     (GObject *obj);
91
92 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
93 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
95 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
97 static void  reset_modified (ModestMsgEditWindow *editor);
98
99 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
100 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
101 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
102 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
103                                     GtkTextIter *start, GtkTextIter *end,
104                                     gpointer userdata);
105 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
106 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
107 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
108                                                          gpointer userdata);
109 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
110                                                  gpointer userdata);
111 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
112                                                  gpointer userdata);
113 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
114 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
115                                                            GdkEventWindowState *event, 
116                                                            gpointer userdata);
117 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
118                                                      ModestRecptEditor *editor);
119 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
120                                                            ModestMsgEditWindow *window);
121
122 /* ModestWindow methods implementation */
123 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
124 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
125 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
126 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
127 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
128                                                    gboolean show_toolbar);
129 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
130                                                            GdkEvent *event,
131                                                            ModestMsgEditWindow *window);
132 static void update_window_title (ModestMsgEditWindow *window);
133 static void update_dimmed (ModestMsgEditWindow *window);
134 static void update_paste_dimming (ModestMsgEditWindow *window);
135 static void update_select_all_dimming (ModestMsgEditWindow *window);
136 static void update_zoom_dimming (ModestMsgEditWindow *window);
137
138 /* Find toolbar */
139 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
140                                                         ModestMsgEditWindow *window);
141 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
142                                                        ModestMsgEditWindow *window);
143 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
144                                                           const gchar *str,
145                                                           GtkTextIter *match_start,
146                                                           GtkTextIter *match_end);
147                                                           
148 static void DEBUG_BUFFER (WPTextBuffer *buffer)
149 {
150 #ifdef DEBUG
151         GtkTextIter iter;
152
153         g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
154         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
155         while (!gtk_text_iter_is_end (&iter)) {
156                 GString *output = g_string_new ("");
157                 GSList *toggled_tags;
158                 GSList *node;
159
160                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
161                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
162                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
163                         GtkTextTag *tag = (GtkTextTag *) node->data;
164                         const gchar *name;
165                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
166                         output = g_string_append (output, name);
167                         g_string_append (output, " ");
168                 }
169                 output = g_string_append (output, "] OPENED [ ");
170                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
171                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
172                         GtkTextTag *tag = (GtkTextTag *) node->data;
173                         const gchar *name;
174                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
175                         output = g_string_append (output, name);
176                         g_string_append (output, " ");
177                 }
178                 output = g_string_append (output, "]\n");
179                 g_message ("%s", output->str);
180                 g_string_free (output, TRUE);
181                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
182         }
183         g_message ("END BUFFER");
184 #endif
185 }
186
187
188 /* static gboolean */
189 /* on_key_pressed (GtkWidget *self, */
190 /*              GdkEventKey *event, */
191 /*              gpointer user_data); */
192
193 static void edit_menu_activated (GtkAction *action,
194                                  gpointer userdata);
195 static void view_menu_activated (GtkAction *action,
196                                  gpointer userdata);
197
198 /* list my signals */
199 enum {
200         /* MY_SIGNAL_1, */
201         /* MY_SIGNAL_2, */
202         LAST_SIGNAL
203 };
204
205 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
206 struct _ModestMsgEditWindowPrivate {
207         GtkWidget   *msg_body;
208         GtkWidget   *header_box;
209         
210         ModestPairList *from_field_protos;
211         GtkWidget   *from_field;
212         
213         GtkWidget   *to_field;
214         GtkWidget   *cc_field;
215         GtkWidget   *bcc_field;
216         GtkWidget   *subject_field;
217         GtkWidget   *attachments_view;
218         GtkWidget   *priority_icon;
219         GtkWidget   *add_attachment_button;
220
221         GtkWidget   *cc_caption;
222         GtkWidget   *bcc_caption;
223         gboolean     update_caption_visibility;
224         GtkWidget   *attachments_caption;
225
226         GtkTextBuffer *text_buffer;
227
228         GtkWidget   *font_size_toolitem;
229         GtkWidget   *font_face_toolitem;
230         GtkWidget   *font_color_button;
231         GSList      *font_items_group;
232         GtkWidget   *font_tool_button_label;
233         GSList      *size_items_group;
234         GtkWidget   *size_tool_button_label;
235         
236         GtkWidget   *find_toolbar;
237         gchar       *last_search;
238
239         GtkWidget   *scroll;
240         GtkWidget   *scroll_area;
241
242         gint last_cid;
243         GList *attachments;
244
245         TnyHeaderFlags priority_flags;
246
247         gdouble zoom_level;
248         
249         gulong      clipboard_change_handler_id;
250
251         TnyMsg      *draft_msg;
252         TnyMsg      *outbox_msg;
253         gboolean    sent;
254 };
255
256 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
257                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
258                                                     ModestMsgEditWindowPrivate))
259 /* globals */
260 static GtkWindowClass *parent_class = NULL;
261
262 /* uncomment the following if you have defined any signals */
263 /* static guint signals[LAST_SIGNAL] = {0}; */
264
265 GType
266 modest_msg_edit_window_get_type (void)
267 {
268         static GType my_type = 0;
269         if (!my_type) {
270                 static const GTypeInfo my_info = {
271                         sizeof(ModestMsgEditWindowClass),
272                         NULL,           /* base init */
273                         NULL,           /* base finalize */
274                         (GClassInitFunc) modest_msg_edit_window_class_init,
275                         NULL,           /* class finalize */
276                         NULL,           /* class data */
277                         sizeof(ModestMsgEditWindow),
278                         1,              /* n_preallocs */
279                         (GInstanceInitFunc) modest_msg_edit_window_init,
280                         NULL
281                 };
282                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
283                                                   "ModestMsgEditWindow",
284                                                   &my_info, 0);
285
286                 wp_text_buffer_library_init ();
287         }
288         return my_type;
289 }
290
291 static void
292 save_state (ModestWindow *self)
293 {
294         modest_widget_memory_save (modest_runtime_get_conf(),
295                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
296 }
297
298
299 static void
300 restore_settings (ModestMsgEditWindow *self)
301 {
302         modest_widget_memory_restore (modest_runtime_get_conf(),
303                                       G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
304 }
305
306
307 static void
308 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
309 {
310         GObjectClass *gobject_class;
311         ModestWindowClass *modest_window_class;
312         gobject_class = (GObjectClass*) klass;
313         modest_window_class = (ModestWindowClass*) klass;
314
315         parent_class            = g_type_class_peek_parent (klass);
316         gobject_class->finalize = modest_msg_edit_window_finalize;
317
318         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
319         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
320         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
321         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
322         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
323         modest_window_class->save_state_func = save_state;
324
325         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
326
327
328 }
329
330 static void
331 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
332 {
333         ModestMsgEditWindowPrivate *priv;
334         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
335
336         priv->msg_body      = NULL;
337         priv->from_field    = NULL;
338         priv->to_field      = NULL;
339         priv->cc_field      = NULL;
340         priv->bcc_field     = NULL;
341         priv->subject_field = NULL;
342         priv->attachments   = NULL;
343         priv->last_cid      = 0;
344         priv->zoom_level    = 1.0;
345
346         priv->cc_caption    = NULL;
347         priv->bcc_caption    = NULL;
348         priv->update_caption_visibility = FALSE;
349
350         priv->priority_flags = 0;
351
352         priv->find_toolbar = NULL;
353         priv->last_search = NULL;
354
355         priv->draft_msg = NULL;
356         priv->outbox_msg = NULL;
357         priv->clipboard_change_handler_id = 0;
358         priv->sent = FALSE;
359 }
360
361
362 /* FIXME: this is a dup from the one in gtk/ */
363
364 /** 
365  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
366  */
367 static ModestPairList*
368 get_transports (void)
369 {
370         GSList *transports = NULL;
371         
372         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
373         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
374                                                              TRUE /* only enabled accounts. */); 
375                                                 
376         GSList *cursor = accounts;
377         while (cursor) {
378                 gchar *account_name = cursor->data;
379                 gchar *from_string  = NULL;
380                 if (account_name) {
381                         from_string = modest_account_mgr_get_from_string (account_mgr,
382                                                                           account_name);
383                 }
384                 
385                 if (from_string && account_name) {
386                         gchar *name = account_name;
387                         ModestPair *pair = modest_pair_new ((gpointer) name,
388                                                 (gpointer) from_string , TRUE);
389                         transports = g_slist_prepend (transports, pair);
390                 }
391                 
392                 cursor = cursor->next;
393         }
394         g_slist_free (accounts); /* only free the accounts, not the elements,
395                                   * because they are used in the pairlist */
396         return transports;
397 }
398
399
400 static void
401 init_window (ModestMsgEditWindow *obj)
402 {
403         GtkWidget *from_caption, *to_caption, *subject_caption;
404         GtkWidget *main_vbox;
405         ModestMsgEditWindowPrivate *priv;
406
407         GtkSizeGroup *size_group;
408         GtkWidget *frame;
409         GtkWidget *subject_box;
410         GtkWidget *attachment_icon;
411         GtkWidget *window_box;
412 #if (GTK_MINOR_VERSION >= 10)
413         GdkAtom deserialize_type;
414 #endif
415         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
416
417         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
418
419         /* Note: This ModestPairList* must exist for as long as the combo
420          * that uses it, because the ModestComboBox uses the ID opaquely, 
421          * so it can't know how to manage its memory. */ 
422         priv->from_field_protos = get_transports ();
423
424         priv->from_field    = modest_combo_box_new (priv->from_field_protos, g_str_equal);
425
426         priv->to_field      = modest_recpt_editor_new ();
427         priv->cc_field      = modest_recpt_editor_new ();
428         priv->bcc_field     = modest_recpt_editor_new ();
429         subject_box = gtk_hbox_new (FALSE, 0);
430         priv->priority_icon = gtk_image_new ();
431         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
432         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
433         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
434         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
435                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
436         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
437         priv->add_attachment_button = gtk_button_new ();
438         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
439         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
440         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
441         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
442         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
443         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
444         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
445         priv->attachments_view = modest_attachments_view_new (NULL);
446         
447         priv->header_box = gtk_vbox_new (FALSE, 0);
448         
449         from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
450         to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
451         priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
452         priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
453         subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
454         priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
455         g_object_unref (size_group);
456
457         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
458         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
459         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
460         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
461         gtk_size_group_add_widget (size_group, priv->subject_field);
462         gtk_size_group_add_widget (size_group, priv->attachments_view);
463         g_object_unref (size_group);
464
465         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
466         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
467         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
468         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
469         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
470         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
471         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
472
473
474         priv->msg_body = wp_text_view_new ();
475         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
476         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
477         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
478         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
479 #if (GTK_MINOR_VERSION >= 10)
480         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
481         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
482                                                                        "wp-text-buffer");
483         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
484                                                          deserialize_type, TRUE);
485 #endif
486         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
487
488         priv->find_toolbar = hildon_find_toolbar_new (NULL);
489         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
490
491 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
492
493         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
494                           G_CALLBACK (text_buffer_refresh_attributes), obj);
495         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
496                           G_CALLBACK (text_buffer_can_undo), obj);
497         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
498                           G_CALLBACK (text_buffer_can_redo), obj);
499         g_signal_connect (G_OBJECT (obj), "window-state-event",
500                           G_CALLBACK (modest_msg_edit_window_window_state_event),
501                           NULL);
502         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
503                                 G_CALLBACK (text_buffer_apply_tag), obj);
504         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
505                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
506         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
507                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
508         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
509                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
510
511         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
512                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
513
514         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
515                           G_CALLBACK (msg_body_focus), obj);
516         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
517                           G_CALLBACK (msg_body_focus), obj);
518         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
519                           "changed", G_CALLBACK (recpt_field_changed), obj);
520         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
521                           "changed", G_CALLBACK (recpt_field_changed), obj);
522         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
523                           "changed", G_CALLBACK (recpt_field_changed), obj);
524         recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
525         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
526
527         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
528         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
529
530         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
531         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
532         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
533         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
534
535         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
536
537         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
538         frame = gtk_frame_new (NULL);
539         gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
540
541         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
542         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
543         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
544         
545         window_box = gtk_vbox_new (FALSE, 0);
546         gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
547         gtk_container_add (GTK_CONTAINER(obj), window_box);
548         priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
549         gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
550         
551         gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->scroll_area), 
552                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
553
554         priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
555                                                               G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
556
557 }
558         
559
560
561 static void
562 modest_msg_edit_window_finalize (GObject *obj)
563 {
564         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
565
566         if (priv->clipboard_change_handler_id > 0) {
567                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), priv->clipboard_change_handler_id);
568                 priv->clipboard_change_handler_id = 0;
569         }
570         
571         if (priv->draft_msg != NULL) {
572                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
573                 if (TNY_IS_HEADER (header)) {
574                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
575                         modest_window_mgr_unregister_header (mgr, header);
576                 }
577                 g_object_unref (priv->draft_msg);
578                 priv->draft_msg = NULL;
579         }
580         if (priv->outbox_msg != NULL) {
581                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
582                 if (TNY_IS_HEADER (header)) {
583                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
584                         modest_window_mgr_unregister_header (mgr, header);
585                 }
586                 g_object_unref (priv->outbox_msg);
587                 priv->outbox_msg = NULL;
588         }
589
590         /* This had to stay alive for as long as the combobox that used it: */
591         modest_pair_list_free (priv->from_field_protos);
592         
593         G_OBJECT_CLASS(parent_class)->finalize (obj);
594 }
595
596 static GtkWidget *
597 menubar_to_menu (GtkUIManager *ui_manager)
598 {
599         GtkWidget *main_menu;
600         GtkWidget *menubar;
601         GList *iter;
602
603         /* Create new main menu */
604         main_menu = gtk_menu_new();
605
606         /* Get the menubar from the UI manager */
607         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
608
609         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
610         while (iter) {
611                 GtkWidget *menu;
612
613                 menu = GTK_WIDGET (iter->data);
614                 gtk_widget_reparent(menu, main_menu);
615
616                 iter = g_list_next (iter);
617         }
618         return main_menu;
619 }
620
621 static GdkPixbuf *
622 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
623 {
624         GdkPixbufLoader *loader;
625         GdkPixbuf *pixbuf;
626
627         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
628
629         if (loader == NULL)
630                 return NULL;
631
632         tny_stream_reset (TNY_STREAM (stream));
633         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
634                 unsigned char read_buffer[128];
635                 gint readed;
636                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
637                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
638                         break;
639         }
640
641         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
642         g_object_ref (pixbuf);
643         gdk_pixbuf_loader_close (loader, NULL);
644         g_object_unref (loader);
645
646         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
647                 GdkPixbuf *new_pixbuf;
648                 gint new_height;
649                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
650                         gdk_pixbuf_get_width (pixbuf);
651                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
652                 g_object_unref (pixbuf);
653                 pixbuf = new_pixbuf;
654         }
655
656         return pixbuf;
657 }
658
659 static void
660 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
661 {
662         ModestMsgEditWindowPrivate *priv;
663         GList *node;
664
665         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
666
667         for (node = attachments; node != NULL; node = g_list_next (node)) {
668                 TnyMimePart *part = (TnyMimePart *) node->data;
669                 const gchar *cid = tny_mime_part_get_content_id (part);
670                 const gchar *mime_type = tny_mime_part_get_content_type (part);
671                 if ((cid != NULL)&&(mime_type != NULL)) {
672                         TnyStream *stream = tny_mime_part_get_stream (part);
673                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
674                         g_object_unref (stream);
675
676                         if (pixbuf != NULL) {
677                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
678                                 g_object_unref (pixbuf);
679                         }
680                 }
681         }
682 }
683
684 static void
685 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
686 {
687         GList *node;
688         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
689
690         for (node = attachments; node != NULL; node = g_list_next (node)) {
691                 TnyMimePart *part = (TnyMimePart *) node->data;
692                 const gchar *cid = tny_mime_part_get_content_id (part);
693                 if (cid != NULL) {
694                         char *invalid = NULL;
695                         gint int_cid = strtol (cid, &invalid, 10);
696                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
697                                 priv->last_cid = int_cid;
698                         }
699                 }
700                 
701         }
702 }
703
704 static void
705 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
706 {
707         TnyHeader *header;
708         const gchar *to, *cc, *bcc, *subject;
709         gchar *body;
710         ModestMsgEditWindowPrivate *priv;
711         GtkTextIter iter;
712         TnyHeaderFlags priority_flags;
713         TnyFolder *msg_folder;
714         
715         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
716         g_return_if_fail (TNY_IS_MSG (msg));
717
718         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
719
720         header = tny_msg_get_header (msg);
721         to      = tny_header_get_to (header);
722         cc      = tny_header_get_cc (header);
723         bcc     = tny_header_get_bcc (header);
724         subject = tny_header_get_subject (header);
725         priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
726
727         if (to)
728                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
729         if (cc) {
730                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
731                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
732                 gtk_widget_show (priv->cc_caption);
733         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
734                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
735                 gtk_widget_hide (priv->cc_caption);
736         }
737         if (bcc) {
738                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
739                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
740                 gtk_widget_show (priv->bcc_caption);
741         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
742                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
743                 gtk_widget_hide (priv->bcc_caption);
744         } 
745         if (subject)
746                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
747         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
748                                                    priority_flags);
749
750         update_window_title (self);
751
752         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
753         body = modest_tny_msg_get_body (msg, TRUE);
754
755         if ((body == NULL)||(body[0] == '\0')) {
756                 g_free (body);
757                 body = modest_text_utils_convert_to_html ("");
758         }
759         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
760         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
761                                             (gchar *) body,
762                                             strlen (body));
763         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
764         g_free (body);
765
766         /* Get the default format required from configuration */
767         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
768                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
769         }
770
771         /* Set the default focus depending on having already a To: field or not */
772         if ((!to)||(*to == '\0')) {
773                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
774         } else {
775                 gtk_widget_grab_focus (priv->msg_body);
776         }
777
778         /* TODO: lower priority, select in the From: combo to the
779            value that comes from msg <- not sure, should it be
780            allowed? */
781         
782         /* Add attachments to the view */
783         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
784         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
785         if (priv->attachments == NULL) {
786                 gtk_widget_hide (priv->attachments_caption);
787         } else {
788                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
789                 gtk_widget_show_all (priv->attachments_caption);
790                 replace_with_attachments (self, priv->attachments);
791         }
792         update_last_cid (self, priv->attachments);
793
794         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
795
796         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
797         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
798
799         reset_modified (self);
800
801         update_dimmed (self);
802         text_buffer_can_undo (priv->text_buffer, FALSE, self);
803         text_buffer_can_redo (priv->text_buffer, FALSE, self);
804
805         /* we should set a reference to the incoming message if it is a draft */
806         msg_folder = tny_msg_get_folder (msg);
807         if (msg_folder) {               
808                 if (modest_tny_folder_is_local_folder (msg_folder)) {
809                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
810                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
811                                 priv->draft_msg = g_object_ref(msg);
812                         if (type == TNY_FOLDER_TYPE_OUTBOX)
813                                 priv->outbox_msg = g_object_ref(msg);
814                 }
815                 g_object_unref (msg_folder);
816         }
817 }
818
819 static void
820 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
821                                 gpointer data)
822 {
823         GList *item_children, *node;
824         GtkWidget *bin_child;
825
826         bin_child = gtk_bin_get_child (GTK_BIN(item));
827
828         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
829         
830         for (node = item_children; node != NULL; node = g_list_next (node)) {
831                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
832                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
833                 }
834         }
835         g_list_free (item_children);
836 }
837
838 static void
839 menu_tool_button_dont_expand (GtkMenuToolButton *item)
840 {
841         GtkWidget *box;
842         GList *item_children, *node;
843
844         box = gtk_bin_get_child (GTK_BIN (item));
845         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
846         item_children = gtk_container_get_children (GTK_CONTAINER (box));
847         
848         for (node = item_children; node != NULL; node = g_list_next (node)) {
849                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
850                 if (GTK_IS_TOGGLE_BUTTON (node->data))
851                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
852                 else if (GTK_IS_BUTTON (node->data))
853                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
854         }
855         g_list_free (item_children);
856 }
857
858
859 static void
860 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
861 {
862         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
863         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
864         GtkWidget *placeholder;
865         GtkWidget *tool_item;
866         gint insert_index;
867         gchar size_text[5];
868         gint size_index;
869         gint font_index;
870         GtkWidget *sizes_menu;
871         GtkWidget *fonts_menu;
872         GSList *radio_group = NULL;
873         GSList *node = NULL;
874         gchar *markup;
875
876         /* Toolbar */
877         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
878         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
879
880         /* should we hide the toolbar? */
881         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
882                 gtk_widget_hide (parent_priv->toolbar);
883
884         /* Font color placeholder */
885         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
886         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
887
888         /* font color */
889         tool_item = GTK_WIDGET (gtk_tool_item_new ());
890         priv->font_color_button = hildon_color_button_new ();
891         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
892         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
893         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
894         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
895         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
896         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
897         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
898
899         /* Font size and face placeholder */
900         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
901         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
902         /* font_size */
903         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
904         priv->size_tool_button_label = gtk_label_new (NULL);
905         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
906         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
907                               size_text,"</span>", NULL);
908         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
909         g_free (markup);
910         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
911         sizes_menu = gtk_menu_new ();
912         priv->size_items_group = NULL;
913         radio_group = NULL;
914         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
915                 GtkWidget *size_menu_item;
916
917                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
918                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
919                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
920                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
921                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
922                 gtk_widget_show (size_menu_item);
923
924                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
925                         
926         }
927
928         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
929                 GtkWidget *item = (GtkWidget *) node->data;
930                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
931                                   window);
932         }
933
934         priv->size_items_group = g_slist_reverse (priv->size_items_group);
935         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
936         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
937         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
938         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
939         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
940         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
941         priv->font_size_toolitem = tool_item;
942
943         /* font face */
944         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
945         priv->font_tool_button_label = gtk_label_new (NULL);
946         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
947         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
948         g_free(markup);
949         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
950         fonts_menu = gtk_menu_new ();
951         priv->font_items_group = NULL;
952         radio_group = NULL;
953         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
954                 GtkWidget *font_menu_item;
955                 GtkWidget *child_label;
956
957                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
958                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
959                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
960                                       wp_get_font_name (font_index), "</span>", NULL);
961                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
962                 g_free (markup);
963                 
964                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
965                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
966                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
967                 gtk_widget_show (font_menu_item);
968
969                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
970                         
971         }
972         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
973                 GtkWidget *item = (GtkWidget *) node->data;
974                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
975                                   window);
976         }
977         priv->font_items_group = g_slist_reverse (priv->font_items_group);
978         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
979         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
980         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
981         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
982         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
983         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
984         priv->font_face_toolitem = tool_item;
985
986         /* Set expand and homogeneous for remaining items */
987         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
988         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
989         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
990         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
991         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
992         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
993         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
994         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
995         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
996
997
998 }
999
1000
1001
1002 ModestWindow*
1003 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
1004 {
1005         GObject *obj;
1006         ModestWindowPrivate *parent_priv;
1007         ModestMsgEditWindowPrivate *priv;
1008         GtkActionGroup *action_group;
1009         GError *error = NULL;
1010         GdkPixbuf *window_icon = NULL;
1011         GtkAction *action;
1012         ModestConf *conf;
1013         gboolean prefer_formatted;
1014         gint file_format;
1015         ModestPair *account_pair = NULL;
1016
1017         g_return_val_if_fail (msg, NULL);
1018         g_return_val_if_fail (account_name, NULL);
1019         
1020         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1021
1022         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1023         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1024
1025         parent_priv->ui_manager = gtk_ui_manager_new();
1026         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1027         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1028
1029         /* Add common actions */
1030         gtk_action_group_add_actions (action_group,
1031                                       modest_msg_edit_action_entries,
1032                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
1033                                       obj);
1034         gtk_action_group_add_toggle_actions (action_group,
1035                                              modest_msg_edit_toggle_action_entries,
1036                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1037                                              obj);
1038         gtk_action_group_add_radio_actions (action_group,
1039                                             modest_msg_edit_alignment_radio_action_entries,
1040                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1041                                             GTK_JUSTIFY_LEFT,
1042                                             G_CALLBACK (modest_ui_actions_on_change_justify),
1043                                             obj);
1044         gtk_action_group_add_radio_actions (action_group,
1045                                             modest_msg_edit_zoom_action_entries,
1046                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1047                                             100,
1048                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
1049                                             obj);
1050         gtk_action_group_add_radio_actions (action_group,
1051                                             modest_msg_edit_priority_action_entries,
1052                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1053                                             0,
1054                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1055                                             obj);
1056         gtk_action_group_add_radio_actions (action_group,
1057                                             modest_msg_edit_file_format_action_entries,
1058                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1059                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1060                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1061                                             obj);
1062         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1063         g_object_unref (action_group);
1064
1065         /* Load the UI definition */
1066         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1067                                          &error);
1068         if (error != NULL) {
1069                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1070                 g_clear_error (&error);
1071         }
1072
1073         /* Add accelerators */
1074         gtk_window_add_accel_group (GTK_WINDOW (obj), 
1075                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1076
1077         /* Menubar */
1078         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1079         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1080
1081         /* Init window */
1082         init_window (MODEST_MSG_EDIT_WINDOW(obj));
1083
1084         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1085                 
1086         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1087
1088         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1089         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1090
1091         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1092
1093         account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1094         if (account_pair != NULL)
1095                 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1096
1097         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
1098
1099         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1100
1101         /* Set window icon */
1102         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1103         if (window_icon) {
1104                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1105                 g_object_unref (window_icon);
1106         }
1107
1108         /* Dim at start clipboard actions */
1109         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1110         gtk_action_set_sensitive (action, FALSE);
1111         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1112         gtk_action_set_sensitive (action, FALSE);
1113         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1114         gtk_action_set_sensitive (action, FALSE);
1115
1116         /* Update select all */
1117         update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1118         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1119         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1120         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1121         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1122
1123         /* set initial state of cc and bcc */
1124         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1125         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1126                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1127         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1128         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1129                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1130
1131         /* Setup the file format */
1132         conf = modest_runtime_get_conf ();
1133         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1134         if (error) {
1135                 g_clear_error (&error);
1136                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1137         } else
1138                 file_format = (prefer_formatted) ? 
1139                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
1140                         MODEST_FILE_FORMAT_PLAIN_TEXT;
1141         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1142
1143         update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1144         priv->update_caption_visibility = TRUE;
1145         
1146         return (ModestWindow*) obj;
1147 }
1148
1149 static gint
1150 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1151 {
1152         GString **string_buffer = (GString **) user_data;
1153
1154         *string_buffer = g_string_append (*string_buffer, buffer);
1155    
1156         return 0;
1157 }
1158
1159 /**
1160  * @result: A new string which should be freed with g_free().
1161  */
1162 static gchar *
1163 get_formatted_data (ModestMsgEditWindow *edit_window)
1164 {
1165         ModestMsgEditWindowPrivate *priv;
1166         GString *string_buffer = g_string_new ("");
1167         
1168         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1169
1170         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1171
1172         return g_string_free (string_buffer, FALSE);
1173                                                                         
1174 }
1175
1176 MsgData * 
1177 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1178 {
1179         MsgData *data;
1180         const gchar *account_name;
1181         ModestMsgEditWindowPrivate *priv;
1182         
1183         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1184
1185         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1186                                                                         
1187         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1188         g_return_val_if_fail (account_name, NULL);
1189         
1190         
1191         /* don't free these (except from) */
1192         data = g_slice_new0 (MsgData);
1193         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1194                                                              account_name);
1195         data->account_name = g_strdup (account_name);
1196         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1197         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1198         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1199         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1200         if (priv->draft_msg) {
1201                 data->draft_msg = g_object_ref (priv->draft_msg);
1202         } 
1203         if (priv->outbox_msg) {
1204                 data->draft_msg = g_object_ref (priv->outbox_msg);
1205         } else {
1206                 data->draft_msg = NULL;
1207         }
1208
1209         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1210         GtkTextIter b, e;
1211         gtk_text_buffer_get_bounds (buf, &b, &e);
1212         data->plain_body = g_strdup (gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE)); /* returns a copy */
1213
1214         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1215                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1216         else
1217                 data->html_body = NULL;
1218
1219         /* deep-copy the data */
1220         GList *cursor = priv->attachments;
1221         data->attachments = NULL;
1222         while (cursor) {
1223                 if (!(TNY_IS_MIME_PART(cursor->data))) {
1224                         g_warning ("strange data in attachment list");
1225                         cursor = g_list_next (cursor);
1226                         continue;
1227                 }
1228                 data->attachments = g_list_append (data->attachments,
1229                                                    g_object_ref (cursor->data));
1230                 cursor = g_list_next (cursor);
1231         }
1232         
1233         data->priority_flags = priv->priority_flags;
1234
1235         return data;
1236 }
1237
1238
1239 static void
1240 unref_gobject (GObject *obj, gpointer data)
1241 {
1242         if (!G_IS_OBJECT(obj))
1243                 return;
1244         g_object_unref (obj);
1245 }
1246
1247 void 
1248 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1249                                                       MsgData *data)
1250 {
1251         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1252
1253         if (!data)
1254                 return;
1255
1256         g_free (data->to);
1257         g_free (data->cc);
1258         g_free (data->bcc);
1259         g_free (data->subject);
1260         g_free (data->plain_body);
1261         g_free (data->html_body);
1262         g_free (data->account_name);
1263         
1264         if (data->draft_msg != NULL) {
1265                 g_object_unref (data->draft_msg);
1266                 data->draft_msg = NULL;
1267         }
1268         
1269         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1270         g_list_free (data->attachments);
1271         
1272         g_slice_free (MsgData, data);
1273 }
1274
1275 ModestMsgEditFormat
1276 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1277 {
1278         gboolean rich_text;
1279         ModestMsgEditWindowPrivate *priv = NULL;
1280         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1281
1282         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1283
1284         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1285         if (rich_text)
1286                 return MODEST_MSG_EDIT_FORMAT_HTML;
1287         else
1288                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1289 }
1290
1291 void
1292 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1293                                    ModestMsgEditFormat format)
1294 {
1295         ModestMsgEditWindowPrivate *priv;
1296
1297         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1298         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1299
1300         switch (format) {
1301         case MODEST_MSG_EDIT_FORMAT_HTML:
1302                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1303                 break;
1304         case MODEST_MSG_EDIT_FORMAT_TEXT:
1305                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1306                 break;
1307         default:
1308                 g_return_if_reached ();
1309         }
1310 }
1311
1312 ModestMsgEditFormatState *
1313 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1314 {
1315         ModestMsgEditFormatState *format_state = NULL;
1316         ModestMsgEditWindowPrivate *priv;
1317         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1318
1319         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1320         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1321
1322         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1323
1324         format_state = g_new0 (ModestMsgEditFormatState, 1);
1325         format_state->bold = buffer_format->bold&0x1;
1326         format_state->italics = buffer_format->italic&0x1;
1327         format_state->bullet = buffer_format->bullet&0x1;
1328         format_state->color = buffer_format->color;
1329         format_state->font_size = buffer_format->font_size;
1330         format_state->font_family = wp_get_font_name (buffer_format->font);
1331         format_state->justification = buffer_format->justification;
1332         g_free (buffer_format);
1333
1334         return format_state;
1335  
1336 }
1337
1338 void
1339 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1340                                          const ModestMsgEditFormatState *format_state)
1341 {
1342         ModestMsgEditWindowPrivate *priv;
1343         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1344         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1345         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1346         g_return_if_fail (format_state != NULL);
1347
1348         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1349         gtk_widget_grab_focus (priv->msg_body);
1350         buffer_format->bold = (format_state->bold != FALSE);
1351         buffer_format->italic = (format_state->italics != FALSE);
1352         buffer_format->color = format_state->color;
1353         buffer_format->font_size = format_state->font_size;
1354         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1355         buffer_format->justification = format_state->justification;
1356         buffer_format->bullet = format_state->bullet;
1357
1358         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1359
1360         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1361         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1362         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1363         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1364         buffer_format->cs.font = (buffer_format->font != current_format->font);
1365         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1366         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1367
1368         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1369         if (buffer_format->cs.bold) {
1370                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1371         }
1372         if (buffer_format->cs.italic) {
1373                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1374         }
1375         if (buffer_format->cs.color) {
1376                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1377         }
1378         if (buffer_format->cs.font_size) {
1379                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1380         }
1381         if (buffer_format->cs.justification) {
1382                 switch (buffer_format->justification) {
1383                 case GTK_JUSTIFY_LEFT:
1384                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1385                         break;
1386                 case GTK_JUSTIFY_CENTER:
1387                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1388                         break;
1389                 case GTK_JUSTIFY_RIGHT:
1390                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1391                         break;
1392                 default:
1393                         break;
1394                 }
1395                         
1396         }
1397         if (buffer_format->cs.font) {
1398                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1399         }
1400         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1401         if (buffer_format->cs.bullet) {
1402           wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1403         }
1404 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1405
1406         g_free (current_format);
1407
1408 }
1409
1410 static void
1411 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1412 {
1413         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1414         GtkAction *action;
1415         ModestWindowPrivate *parent_priv;
1416         ModestMsgEditWindowPrivate *priv;
1417         GtkWidget *new_size_menuitem;
1418         GtkWidget *new_font_menuitem;
1419         
1420         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1421         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1422
1423         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1424                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1425                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1426                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1427         } else {
1428                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1429                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1430                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1431         }
1432
1433         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1434         
1435         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1436         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1437
1438         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1439         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1440
1441         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1442         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1443
1444         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1445                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1446                                          window);
1447         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1448         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1449                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1450                                            window);
1451
1452         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1453                                                       buffer_format->font_size))->data);
1454         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1455                 GtkWidget *label;
1456                 gchar *markup;
1457
1458                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1459                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1460                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1461                 g_free (markup);
1462                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1463                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1464                                                  window);
1465                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1466                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1467                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1468                                                    window);
1469         }
1470
1471         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1472                                                       buffer_format->font))->data);
1473         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1474                 GtkWidget *label;
1475                 gchar *markup;
1476
1477                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1478                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1479                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1480                 g_free (markup);
1481                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1482                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1483                                                  window);
1484                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1485                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1486                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1487                                                    window);
1488         }
1489
1490         g_free (buffer_format);
1491
1492 }
1493
1494
1495 void
1496 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1497 {
1498         
1499         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1500         ModestMsgEditWindowPrivate *priv;
1501         GtkWidget *dialog = NULL;
1502         gint response;
1503         const GdkColor *new_color = NULL;
1504         
1505         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1506         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1507         
1508 #ifdef MODEST_HILDON_VERSION_0  
1509         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1510         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1511 #else
1512         dialog = hildon_color_chooser_new ();
1513         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1514 #endif /*MODEST_HILDON_VERSION_0*/              
1515         g_free (buffer_format);
1516
1517         response = gtk_dialog_run (GTK_DIALOG (dialog));
1518         switch (response) {
1519         case GTK_RESPONSE_OK: {
1520 #ifdef MODEST_HILDON_VERSION_0
1521                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1522 #else
1523                 GdkColor col;
1524                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1525                 new_color = &col;
1526 #endif /*MODEST_HILDON_VERSION_0*/
1527         }
1528
1529         break;
1530         default:
1531                 break;
1532         }
1533         gtk_widget_destroy (dialog);
1534
1535         if (new_color != NULL)
1536                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1537
1538 }
1539
1540 void
1541 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1542 {
1543         
1544         ModestMsgEditWindowPrivate *priv;
1545         GtkWidget *dialog = NULL;
1546         gint response;
1547         GdkColor *old_color = NULL;
1548         const GdkColor *new_color = NULL;
1549         
1550         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1551         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1552         
1553 #ifdef MODEST_HILDON_VERSION_0  
1554         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1555         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1556 #else
1557         dialog = hildon_color_chooser_new ();
1558         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1559 #endif /*MODEST_HILDON_VERSION_9*/              
1560
1561         response = gtk_dialog_run (GTK_DIALOG (dialog));
1562         switch (response) {
1563         case GTK_RESPONSE_OK: {
1564 #ifdef MODEST_HILDON_VERSION_0
1565                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1566 #else
1567                 GdkColor col;
1568                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1569                 new_color = &col;
1570 #endif /*MODEST_HILDON_VERSION_0*/
1571           }
1572                 break;
1573         default:
1574                 break;
1575         }
1576         gtk_widget_destroy (dialog);
1577
1578         if (new_color != NULL)
1579                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1580
1581 }
1582
1583 static TnyStream* create_stream_for_uri (const gchar* uri)
1584 {
1585         if (!uri)
1586                 return NULL;
1587                 
1588         TnyStream *result = NULL;
1589
1590         GnomeVFSHandle *handle = NULL;
1591         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1592         if (test == GNOME_VFS_OK) {
1593                 /* Create the tinymail stream: */
1594                 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1595                 result = TNY_STREAM (tny_vfs_stream_new (handle));
1596         }
1597         
1598         return result;
1599 }
1600
1601 void
1602 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1603 {
1604         
1605         ModestMsgEditWindowPrivate *priv;
1606         GtkWidget *dialog = NULL;
1607         gint response = 0;
1608         GSList *uris = NULL;
1609         GSList *uri_node = NULL;
1610         
1611         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1612         
1613         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1614         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1615         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1616
1617         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1618
1619         response = gtk_dialog_run (GTK_DIALOG (dialog));
1620         switch (response) {
1621         case GTK_RESPONSE_OK:
1622                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1623                 break;
1624         default:
1625                 break;
1626         }
1627         gtk_widget_destroy (dialog);
1628
1629         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1630                 const gchar *uri;
1631                 GnomeVFSHandle *handle = NULL;
1632                 GnomeVFSResult result;
1633                 GtkTextIter position;
1634                 GtkTextMark *insert_mark;
1635
1636                 uri = (const gchar *) uri_node->data;
1637                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1638                 if (result == GNOME_VFS_OK) {
1639                         GdkPixbuf *pixbuf;
1640                         GnomeVFSFileInfo info;
1641                         gchar *filename, *basename, *escaped_filename;
1642                         TnyMimePart *mime_part;
1643                         gchar *content_id;
1644                         const gchar *mime_type = NULL;
1645                         GnomeVFSURI *vfs_uri;
1646
1647                         vfs_uri = gnome_vfs_uri_new (uri);
1648
1649                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1650                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1651                         g_free (escaped_filename);
1652                         gnome_vfs_uri_unref (vfs_uri);
1653
1654                         if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1655                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
1656                             == GNOME_VFS_OK)
1657                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1658
1659                         mime_part = tny_platform_factory_new_mime_part
1660                                 (modest_runtime_get_platform_factory ());
1661                                 
1662                         TnyStream *stream = create_stream_for_uri (uri);
1663                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1664                         
1665                         content_id = g_strdup_printf ("%d", priv->last_cid);
1666                         tny_mime_part_set_content_id (mime_part, content_id);
1667                         g_free (content_id);
1668                         priv->last_cid++;
1669                         
1670                         basename = g_path_get_basename (filename);
1671                         tny_mime_part_set_filename (mime_part, basename);
1672                         g_free (basename);
1673
1674                         pixbuf = pixbuf_from_stream (stream, mime_type);
1675                         
1676                         if (pixbuf != NULL) {
1677                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1678                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1679                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1680                         } 
1681
1682                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1683                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1684                                                                 mime_part);
1685                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1686                         gtk_widget_show_all (priv->attachments_caption);
1687                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1688                         g_free (filename);
1689
1690                 }
1691         }
1692
1693
1694 }
1695
1696 void
1697 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1698 {
1699         
1700         ModestMsgEditWindowPrivate *priv;
1701         GtkWidget *dialog = NULL;
1702         gint response = 0;
1703         GSList *uris = NULL;
1704         GSList *uri_node;
1705         
1706         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1707         
1708         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1709         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1710         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1711
1712         response = gtk_dialog_run (GTK_DIALOG (dialog));
1713         switch (response) {
1714         case GTK_RESPONSE_OK:
1715                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1716                 break;
1717         default:
1718                 break;
1719         }
1720         gtk_widget_destroy (dialog);
1721
1722         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1723                 const gchar *uri = (const gchar *) uri_node->data;
1724                 modest_msg_edit_window_attach_file_one (window, uri);
1725         }
1726         g_slist_foreach (uris, (GFunc) g_free, NULL);
1727         g_slist_free (uris);
1728 }
1729
1730 void
1731 modest_msg_edit_window_attach_file_one (
1732                 ModestMsgEditWindow *window,
1733                 const gchar *uri)
1734 {
1735         g_return_if_fail (window);
1736         g_return_if_fail (uri);
1737                 
1738         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1739         
1740         
1741         GnomeVFSHandle *handle = NULL;
1742         GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1743         if (result == GNOME_VFS_OK) {
1744                 TnyMimePart *mime_part;
1745                 TnyStream *stream;
1746                 const gchar *mime_type = NULL;
1747                 gchar *basename;
1748                 gchar *escaped_filename;
1749                 gchar *filename;
1750                 gchar *content_id;
1751                 GnomeVFSFileInfo info;
1752                 GnomeVFSURI *vfs_uri;
1753
1754                 vfs_uri = gnome_vfs_uri_new (uri);
1755                 
1756
1757                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1758                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1759                 g_free (escaped_filename);
1760                 gnome_vfs_uri_unref (vfs_uri);
1761                 
1762                 if (gnome_vfs_get_file_info (uri, 
1763                                              &info, 
1764                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1765                                              GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1766                     == GNOME_VFS_OK)
1767                         mime_type = gnome_vfs_file_info_get_mime_type (&info);
1768                 mime_part = tny_platform_factory_new_mime_part
1769                         (modest_runtime_get_platform_factory ());
1770                 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1771                 
1772                 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1773                 
1774                 content_id = g_strdup_printf ("%d", priv->last_cid);
1775                 tny_mime_part_set_content_id (mime_part, content_id);
1776                 g_free (content_id);
1777                 priv->last_cid++;
1778                 
1779                 basename = g_path_get_basename (filename);
1780                 tny_mime_part_set_filename (mime_part, basename);
1781                 g_free (basename);
1782                 
1783                 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1784                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1785                                                         mime_part);
1786                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1787                 gtk_widget_show_all (priv->attachments_caption);
1788                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1789                 g_free (filename);
1790         }
1791 }
1792
1793 void
1794 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1795                                           GList *att_list)
1796 {
1797         ModestMsgEditWindowPrivate *priv;
1798         gboolean clean_list = FALSE;
1799
1800         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1801         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1802
1803         if (att_list == NULL) {
1804                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1805                 clean_list = TRUE;
1806         }
1807
1808         if (att_list == NULL) {
1809                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1810         } else {
1811                 GtkWidget *confirmation_dialog = NULL;
1812                 gboolean dialog_response;
1813                 GList *node;
1814                 gchar *message = NULL;
1815                 const gchar *filename = NULL;
1816
1817                 if (att_list->next == NULL) {
1818                         filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1819                 } else {
1820                         filename = "";
1821                 }
1822                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1823                                                     att_list->next == NULL), filename);
1824                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1825                 g_free (message);
1826                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1827                 gtk_widget_destroy (confirmation_dialog);
1828                 if (!dialog_response) {
1829                         if (clean_list)
1830                                 g_list_free (att_list);
1831                         return;
1832                 }
1833                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1834
1835                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1836                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1837                         const gchar *att_id;
1838                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1839
1840                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1841                                                                    mime_part);
1842                         if (priv->attachments == NULL)
1843                                 gtk_widget_hide (priv->attachments_caption);
1844                         att_id = tny_mime_part_get_content_id (mime_part);
1845                         if (att_id != NULL)
1846                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1847                                                                  att_id);
1848                         g_object_unref (mime_part);
1849                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1850                 }
1851         }
1852
1853         if (clean_list)
1854                 g_list_free (att_list);
1855 }
1856
1857 static void
1858 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1859                                             gpointer userdata)
1860 {
1861         ModestMsgEditWindowPrivate *priv;
1862         GdkColor *new_color;
1863         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1864         
1865 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
1866         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1867 #else 
1868         GdkColor col;
1869         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1870         new_color = &col;
1871 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1872
1873         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1874         
1875         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1876
1877 }
1878
1879 static void
1880 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1881                                     gpointer userdata)
1882 {
1883         ModestMsgEditWindowPrivate *priv;
1884         gint new_size_index;
1885         ModestMsgEditWindow *window;
1886         GtkWidget *label;
1887         
1888         window = MODEST_MSG_EDIT_WINDOW (userdata);
1889         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1890         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1891
1892         if (gtk_check_menu_item_get_active (menu_item)) {
1893                 gchar *markup;
1894                 WPTextBufferFormat format;
1895
1896                 memset (&format, 0, sizeof (format));
1897                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1898
1899                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1900                 
1901                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1902                 format.cs.font_size = TRUE;
1903                 format.cs.text_position = TRUE;
1904                 format.cs.font = TRUE;
1905                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1906 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1907
1908                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1909                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
1910                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1911                 
1912                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1913                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1914                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1915                 g_free (markup);
1916         }
1917 }
1918
1919 static void
1920 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1921                                     gpointer userdata)
1922 {
1923         ModestMsgEditWindowPrivate *priv;
1924         gint new_font_index;
1925         ModestMsgEditWindow *window;
1926         GtkWidget *label;
1927         
1928         window = MODEST_MSG_EDIT_WINDOW (userdata);
1929         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1930         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1931
1932         if (gtk_check_menu_item_get_active (menu_item)) {
1933                 gchar *markup;
1934
1935                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1936                 
1937                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1938
1939                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1940                                                    (gpointer) new_font_index))
1941                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1942                 
1943                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1944                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1945                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1946                 g_free (markup);
1947         }
1948 }
1949
1950 static void
1951 modest_msg_edit_window_set_zoom (ModestWindow *window,
1952                                  gdouble zoom)
1953 {
1954         ModestMsgEditWindowPrivate *priv;
1955         ModestWindowPrivate *parent_priv;
1956         GtkRadioAction *zoom_radio_action;
1957      
1958         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1959
1960         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1961         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1962         priv->zoom_level = zoom;
1963         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
1964
1965         /* Zoom level menu options should be updated with the current zoom level */
1966         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1967         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1968                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1969 #ifdef MODEST_HAVE_HILDON0_WIDGETS
1970         /* FIXME: Not availible before Gtk 2.10 */
1971 #else
1972         gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
1973 #endif
1974 }
1975
1976 static gdouble
1977 modest_msg_edit_window_get_zoom (ModestWindow *window)
1978 {
1979         ModestMsgEditWindowPrivate *priv;
1980      
1981         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1982
1983         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1984         return priv->zoom_level;
1985 }
1986
1987 static gboolean
1988 zoom_allowed (ModestMsgEditWindow *window)
1989 {
1990         GtkWidget *focus;
1991
1992         focus = gtk_window_get_focus (GTK_WINDOW (window));
1993         return (focus != NULL && WP_IS_TEXT_VIEW (focus));
1994 }
1995
1996 static gboolean
1997 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1998 {
1999         ModestWindowPrivate *parent_priv;
2000         GtkRadioAction *zoom_radio_action;
2001         GSList *group, *node;
2002
2003         /* First we check if the text view is focused. If not, zooming is not allowed */
2004         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2005                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2006                 return FALSE;
2007         }
2008
2009         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2010         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
2011                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2012
2013         group = gtk_radio_action_get_group (zoom_radio_action);
2014
2015         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2016                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2017                 return FALSE;
2018         }
2019
2020         for (node = group; node != NULL; node = g_slist_next (node)) {
2021                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2022                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2023                         return TRUE;
2024                 }
2025         }
2026         return FALSE;
2027 }
2028
2029 static gboolean
2030 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2031 {
2032         ModestWindowPrivate *parent_priv;
2033         GtkRadioAction *zoom_radio_action;
2034         GSList *group, *node;
2035
2036         /* First we check if the text view is focused. If not, zooming is not allowed */
2037         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2038                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2039                 return FALSE;
2040         }
2041
2042         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2043         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
2044                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2045
2046         group = gtk_radio_action_get_group (zoom_radio_action);
2047
2048         for (node = group; node != NULL; node = g_slist_next (node)) {
2049                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2050                         if (node->next != NULL) {
2051                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2052                                 return TRUE;
2053                         } else
2054                                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2055                         break;
2056                 }
2057         }
2058         return FALSE;
2059 }
2060
2061 static gboolean
2062 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2063 {
2064         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2065                 ModestWindowPrivate *parent_priv;
2066                 ModestWindowMgr *mgr;
2067                 gboolean is_fullscreen;
2068                 GtkAction *fs_toggle_action;
2069                 gboolean active;
2070
2071                 mgr = modest_runtime_get_window_mgr ();
2072                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2073
2074                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2075                 
2076                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2077                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2078                 if (is_fullscreen != active)
2079                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2080         }
2081
2082         return FALSE;
2083
2084 }
2085
2086 void
2087 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2088 {
2089         ModestWindowPrivate *parent_priv;
2090         GtkAction *fs_toggle_action;
2091         gboolean active;
2092
2093         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2094
2095         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2096         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2097         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2098 }
2099
2100 void
2101 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2102                                 gboolean show)
2103 {
2104         ModestMsgEditWindowPrivate *priv = NULL;
2105         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2106
2107         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2108         if (!priv->update_caption_visibility)
2109                 return;
2110
2111         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2112         if (show)
2113                 gtk_widget_show (priv->cc_caption);
2114         else
2115                 gtk_widget_hide (priv->cc_caption);
2116
2117         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2118 }
2119
2120 void
2121 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2122                                  gboolean show)
2123 {
2124         ModestMsgEditWindowPrivate *priv = NULL;
2125         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2126
2127         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2128         if (!priv->update_caption_visibility)
2129                 return;
2130
2131         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2132         if (show)
2133                 gtk_widget_show (priv->bcc_caption);
2134         else
2135                 gtk_widget_hide (priv->bcc_caption);
2136
2137         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2138 }
2139
2140 static void
2141 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2142                                          ModestRecptEditor *editor)
2143 {
2144         ModestMsgEditWindowPrivate *priv;
2145
2146         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2147         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2148         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2149
2150         if (editor == NULL) {
2151                 GtkWidget *view_focus;
2152                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2153
2154                 /* This code should be kept in sync with ModestRecptEditor. The
2155                    textview inside the recpt editor is the one that really gets the
2156                    focus. As it's inside a scrolled window, and this one inside the
2157                    hbox recpt editor inherits from, we'll need to go up in the 
2158                    hierarchy to know if the text view is part of the recpt editor
2159                    or if it's a different text entry */
2160
2161                 if (gtk_widget_get_parent (view_focus)) {
2162                         GtkWidget *first_parent;
2163
2164                         first_parent = gtk_widget_get_parent (view_focus);
2165                         if (gtk_widget_get_parent (first_parent) && 
2166                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2167                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2168                         }
2169                 }
2170
2171                 if (editor == NULL)
2172                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2173
2174         }
2175
2176         modest_address_book_select_addresses (editor);
2177
2178 }
2179
2180 void
2181 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2182 {
2183         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2184
2185         modest_msg_edit_window_open_addressbook (window, NULL);
2186 }
2187
2188 static void
2189 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2190                                      gboolean show_toolbar)
2191 {
2192         ModestWindowPrivate *parent_priv;
2193         
2194         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2195         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2196
2197         /* FIXME: we can not just use the code of
2198            modest_msg_edit_window_setup_toolbar because it has a
2199            mixture of both initialization and creation code. */
2200
2201         if (show_toolbar)
2202                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2203         else
2204                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2205 }
2206
2207 void
2208 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2209                                            TnyHeaderFlags priority_flags)
2210 {
2211         ModestMsgEditWindowPrivate *priv;
2212         ModestWindowPrivate *parent_priv;
2213
2214         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2215
2216         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2217         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2218         priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2219
2220         if (priv->priority_flags != priority_flags) {
2221                 GtkAction *priority_action = NULL;
2222
2223                 priv->priority_flags = priority_flags;
2224
2225                 switch (priority_flags) {
2226                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2227                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2228                         gtk_widget_show (priv->priority_icon);
2229                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2230                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2231                         break;
2232                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2233                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2234                         gtk_widget_show (priv->priority_icon);
2235                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2236                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2237                         break;
2238                 default:
2239                         gtk_widget_hide (priv->priority_icon);
2240                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2241                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2242                         break;
2243                 }
2244                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2245                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2246         }
2247 }
2248
2249 void
2250 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2251                                         gint file_format)
2252 {
2253         ModestMsgEditWindowPrivate *priv;
2254         ModestWindowPrivate *parent_priv;
2255         gint current_format;
2256
2257         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2258
2259         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2260         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2261
2262         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2263                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2264
2265         if (current_format != file_format) {
2266                 switch (file_format) {
2267                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2268                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2269                         break;
2270                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2271                 {
2272                         GtkWidget *dialog;
2273                         gint response;
2274                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2275                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2276                         gtk_widget_destroy (dialog);
2277                         if (response == GTK_RESPONSE_OK) {
2278                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2279                         } else {
2280                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2281                                 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2282                         }
2283                 }
2284                         break;
2285                 }
2286                 update_dimmed (window);
2287         }
2288 }
2289
2290 void
2291 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2292 {
2293         GtkWidget *dialog;
2294         ModestMsgEditWindowPrivate *priv;
2295         WPTextBufferFormat oldfmt, fmt;
2296         gint old_position = 0;
2297         gint response = 0;
2298         gint position = 0;
2299         gint font_size;
2300         GdkColor *color = NULL;
2301         gboolean bold, bold_set, italic, italic_set;
2302         gboolean underline, underline_set;
2303         gboolean strikethrough, strikethrough_set;
2304         gboolean position_set;
2305         gboolean font_size_set, font_set, color_set;
2306         gchar *font_name;
2307
2308         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2309         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2310         
2311         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2312
2313         /* First we get the currently selected font information */
2314         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2315         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2316
2317         switch (oldfmt.text_position) {
2318         case TEXT_POSITION_NORMAL:
2319                 old_position = 0;
2320                 break;
2321         case TEXT_POSITION_SUPERSCRIPT:
2322                 old_position = 1;
2323                 break;
2324         default:
2325                 old_position = -1;
2326                 break;
2327         }
2328
2329         g_object_set (G_OBJECT (dialog),
2330                       "bold", oldfmt.bold != FALSE,
2331                       "bold-set", !oldfmt.cs.bold,
2332                       "underline", oldfmt.underline != FALSE,
2333                       "underline-set", !oldfmt.cs.underline,
2334                       "italic", oldfmt.italic != FALSE,
2335                       "italic-set", !oldfmt.cs.italic,
2336                       "strikethrough", oldfmt.strikethrough != FALSE,
2337                       "strikethrough-set", !oldfmt.cs.strikethrough,
2338                       "color", &oldfmt.color,
2339                       "color-set", !oldfmt.cs.color,
2340                       "size", wp_font_size[oldfmt.font_size],
2341                       "size-set", !oldfmt.cs.font_size,
2342                       "position", old_position,
2343                       "position-set", !oldfmt.cs.text_position,
2344                       "family", wp_get_font_name (oldfmt.font),
2345                       "family-set", !oldfmt.cs.font,
2346                       NULL);
2347
2348         gtk_widget_show_all (dialog);
2349         response = gtk_dialog_run (GTK_DIALOG (dialog));
2350         if (response == GTK_RESPONSE_OK) {
2351
2352                 g_object_get( dialog,
2353                               "bold", &bold,
2354                               "bold-set", &bold_set,
2355                               "underline", &underline,
2356                               "underline-set", &underline_set,
2357                               "italic", &italic,
2358                               "italic-set", &italic_set,
2359                               "strikethrough", &strikethrough,
2360                               "strikethrough-set", &strikethrough_set,
2361                               "color", &color,
2362                               "color-set", &color_set,
2363                               "size", &font_size,
2364                               "size-set", &font_size_set,
2365                               "family", &font_name,
2366                               "family-set", &font_set,
2367                               "position", &position,
2368                               "position-set", &position_set,
2369                               NULL );
2370                 
2371         }       
2372
2373         if (response == GTK_RESPONSE_OK) {
2374                 memset(&fmt, 0, sizeof(fmt));
2375                 if (bold_set) {
2376                         fmt.bold = bold;
2377                         fmt.cs.bold = TRUE;
2378                 }
2379                 if (italic_set) {
2380                         fmt.italic = italic;
2381                         fmt.cs.italic = TRUE;
2382                 }
2383                 if (underline_set) {
2384                         fmt.underline = underline;
2385                         fmt.cs.underline = TRUE;
2386                 }
2387                 if (strikethrough_set) {
2388                         fmt.strikethrough = strikethrough;
2389                         fmt.cs.strikethrough = TRUE;
2390                 }
2391                 if (position_set) {
2392                         fmt.text_position =
2393                                 ( position == 0 )
2394                                 ? TEXT_POSITION_NORMAL
2395                                 : ( ( position == 1 )
2396                                     ? TEXT_POSITION_SUPERSCRIPT
2397                                     : TEXT_POSITION_SUBSCRIPT );
2398                         fmt.cs.text_position = TRUE;
2399                 }
2400                 if (color_set) {
2401                         fmt.color = *color;
2402                         fmt.cs.color = TRUE;
2403                 }
2404                 if (font_set) {
2405                         fmt.font = wp_get_font_index(font_name,
2406                                                      DEFAULT_FONT);
2407                         fmt.cs.font = TRUE;
2408                 }
2409                 g_free(font_name);
2410                 if (font_size_set) {
2411                         fmt.font_size = wp_get_font_size_index(
2412                                 font_size, DEFAULT_FONT_SIZE);
2413                         fmt.cs.font_size = TRUE;
2414                 }
2415                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2416         }
2417         gtk_widget_destroy (dialog);
2418         
2419         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2420 }
2421
2422 void
2423 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2424 {
2425         ModestMsgEditWindowPrivate *priv;
2426
2427         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2428         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2429         
2430         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2431
2432         update_dimmed (window);
2433
2434 }
2435
2436 void
2437 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2438 {
2439         ModestMsgEditWindowPrivate *priv;
2440
2441         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2442         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2443         
2444         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2445
2446         update_dimmed (window);
2447
2448 }
2449
2450 static void
2451 update_dimmed (ModestMsgEditWindow *window)
2452 {
2453         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2454         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2455         GtkAction *action;
2456         GtkWidget *widget;
2457         gboolean rich_text;
2458         gboolean editor_focused;
2459
2460         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2461         editor_focused = gtk_widget_is_focus (priv->msg_body);
2462
2463         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2464         gtk_action_set_sensitive (action, rich_text && editor_focused);
2465         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2466         gtk_action_set_sensitive (action, rich_text && editor_focused);
2467         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2468         gtk_action_set_sensitive (action, rich_text && editor_focused);
2469         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2470         gtk_action_set_sensitive (action, rich_text && editor_focused);
2471         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2472         gtk_action_set_sensitive (action, rich_text && editor_focused);
2473         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2474         gtk_action_set_sensitive (action, rich_text && editor_focused);
2475         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2476         gtk_action_set_sensitive (action, rich_text && editor_focused);
2477         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2478         gtk_action_set_sensitive (action, rich_text && editor_focused);
2479         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2480         gtk_action_set_sensitive (action, rich_text && editor_focused);
2481         widget = priv->font_color_button;
2482         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2483         widget = priv->font_size_toolitem;
2484         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2485         widget = priv->font_face_toolitem;
2486         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2487 }
2488
2489 static void
2490 setup_insensitive_handlers (ModestMsgEditWindow *window)
2491 {
2492         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2493         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2494         GtkWidget *widget;
2495
2496         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2497         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2498         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2499         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2500         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2501         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2502         widget = priv->font_color_button;
2503         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2504         widget = priv->font_size_toolitem;
2505         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2506         widget = priv->font_face_toolitem;
2507         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2508
2509 }
2510
2511 static void  
2512 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2513 {
2514         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2515         GtkAction *action;
2516
2517         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2518         gtk_action_set_sensitive (action, can_undo);
2519 }
2520
2521 static void  
2522 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2523 {
2524         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2525         GtkAction *action;
2526
2527         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2528         gtk_action_set_sensitive (action, can_redo);
2529 }
2530
2531 static void
2532 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2533 {
2534         GtkTextIter iter;
2535         GtkTextIter match_start, match_end;
2536
2537         if (image_id == NULL)
2538                 return;
2539
2540         gtk_text_buffer_get_start_iter (buffer, &iter);
2541
2542         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2543                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2544                 GSList *node;
2545                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2546                         GtkTextTag *tag = (GtkTextTag *) node->data;
2547                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2548                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2549                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2550                                         gint offset;
2551                                         offset = gtk_text_iter_get_offset (&match_start);
2552                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2553                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2554                                 }
2555                         }
2556                 }
2557                 gtk_text_iter_forward_char (&iter);
2558         }
2559 }
2560
2561 static gboolean
2562 msg_body_focus (GtkWidget *focus,
2563                 GdkEventFocus *event,
2564                 gpointer userdata)
2565 {
2566         
2567         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2568         return FALSE;
2569 }
2570
2571 static void
2572 recpt_field_changed (GtkTextBuffer *buffer,
2573                   ModestMsgEditWindow *editor)
2574 {
2575         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2576         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2577         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2578         gboolean dim = FALSE;
2579         GtkAction *action;
2580
2581         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2582         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2583         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2584         
2585         dim = ((gtk_text_buffer_get_char_count (to_buffer) + 
2586                 gtk_text_buffer_get_char_count (cc_buffer) +
2587                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2588                         
2589         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2590         gtk_action_set_sensitive (action, !dim);
2591         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2592         gtk_action_set_sensitive (action, !dim);
2593 }
2594
2595 static void  
2596 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2597 {
2598         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2599 }
2600
2601 static void
2602 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2603 {
2604         gboolean rich_text, editor_focused;
2605
2606         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2607         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2608         editor_focused = gtk_widget_is_focus (priv->msg_body);
2609
2610         if (!rich_text)
2611                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2612         else if (!editor_focused)
2613                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2614 }
2615
2616 static void
2617 reset_modified (ModestMsgEditWindow *editor)
2618 {
2619         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2620         GtkTextBuffer *buffer;
2621
2622         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2623         gtk_text_buffer_set_modified (buffer, FALSE);
2624         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2625         gtk_text_buffer_set_modified (buffer, FALSE);
2626         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2627         gtk_text_buffer_set_modified (buffer, FALSE);
2628         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2629 }
2630
2631 gboolean
2632 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2633 {
2634         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2635         GtkTextBuffer *buffer;
2636
2637         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2638         if (gtk_text_buffer_get_modified (buffer))
2639                 return TRUE;
2640         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2641         if (gtk_text_buffer_get_modified (buffer))
2642                 return TRUE;
2643         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2644         if (gtk_text_buffer_get_modified (buffer))
2645                 return TRUE;
2646         if (gtk_text_buffer_get_modified (priv->text_buffer))
2647                 return TRUE;
2648
2649         return FALSE;
2650 }
2651
2652 gboolean
2653 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2654 {
2655         ModestMsgEditWindowPrivate *priv = NULL;
2656         
2657         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2658         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2659
2660         /* check if there's no recipient added */
2661         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2662             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2663             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2664                 /* no recipient contents, then select contacts */
2665                 modest_msg_edit_window_open_addressbook (window, NULL);
2666                 return FALSE;
2667         }
2668
2669         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook))
2670                 return FALSE;
2671         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook))
2672                 return FALSE;
2673         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook))
2674                 return FALSE;
2675
2676         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2677
2678         return TRUE;
2679
2680 }
2681
2682 static void
2683 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2684                                                ModestMsgEditWindow *window)
2685 {
2686         modest_msg_edit_window_offer_attach_file (window);
2687 }
2688
2689 static void
2690 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2691                                                GdkEvent *event,
2692                                                ModestMsgEditWindow *window)
2693 {
2694         ModestWindowPrivate *parent_priv;
2695         ModestMsgEditWindowPrivate *priv;
2696         GtkAction *action;
2697         gboolean has_selection;
2698         GtkWidget *focused;
2699         GList *selected_attachments = NULL;
2700         gint n_att_selected = 0;
2701
2702         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2703         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2704
2705         if (!GTK_WIDGET_VISIBLE (window))
2706                 return;
2707         has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
2708         focused = gtk_window_get_focus (GTK_WINDOW (window));
2709
2710         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2711         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2712         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2713         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2714
2715         selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2716         n_att_selected = g_list_length (selected_attachments);
2717         g_list_free (selected_attachments);
2718
2719         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2720         gtk_action_set_sensitive (action, n_att_selected == 1);
2721         
2722         update_paste_dimming (window);
2723 }
2724
2725 static void 
2726 update_window_title (ModestMsgEditWindow *window)
2727 {
2728         ModestMsgEditWindowPrivate *priv = NULL;
2729         const gchar *subject;
2730
2731         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2732         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2733         if (subject == NULL || subject[0] == '\0')
2734                 subject = _("mail_va_new_email");
2735
2736         gtk_window_set_title (GTK_WINDOW (window), subject);
2737
2738 }
2739
2740 static void  
2741 subject_field_changed (GtkEditable *editable, 
2742                        ModestMsgEditWindow *window)
2743 {
2744         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2745         update_window_title (window);
2746         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2747 }
2748
2749 gboolean
2750 message_is_empty (ModestMsgEditWindow *window)
2751 {
2752         ModestMsgEditWindowPrivate *priv = NULL;
2753
2754         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2755         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2756         
2757         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2758          * so we can ignore markup.
2759          */
2760         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2761         gint count = 0;
2762         if (buf)
2763                 count = gtk_text_buffer_get_char_count (buf);
2764                 
2765         return count == 0;
2766 }
2767         
2768 void
2769 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2770                                             gboolean show)
2771 {
2772         ModestMsgEditWindowPrivate *priv = NULL;
2773
2774         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2775         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2776
2777         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2778
2779         if (show) {
2780                 gtk_widget_show_all (priv->find_toolbar);
2781                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2782         } else {
2783                 gtk_widget_hide_all (priv->find_toolbar);
2784                 gtk_widget_grab_focus (priv->msg_body);
2785         }
2786     
2787 }
2788
2789 static gboolean 
2790 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2791                                           const gchar *str,
2792                                           GtkTextIter *match_start,
2793                                           GtkTextIter *match_end)
2794 {
2795         GtkTextIter end_iter;
2796         gchar *str_casefold;
2797         gint str_chars_n;
2798         gchar *range_text;
2799         gchar *range_casefold;
2800         gint offset;
2801         gint range_chars_n;
2802         gboolean result = FALSE;
2803
2804         if (str == NULL)
2805                 return TRUE;
2806         
2807         /* get end iter */
2808         end_iter = *iter;
2809         gtk_text_iter_forward_to_end (&end_iter);
2810
2811         str_casefold = g_utf8_casefold (str, -1);
2812         str_chars_n = strlen (str);
2813
2814         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2815         range_casefold = g_utf8_casefold (range_text, -1);
2816         range_chars_n = strlen (range_casefold);
2817
2818         if (range_chars_n < str_chars_n) {
2819                 g_free (str_casefold);
2820                 g_free (range_text);
2821                 g_free (range_casefold);
2822                 return FALSE;
2823         }
2824
2825         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2826                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2827                 if (!g_utf8_collate (range_subtext, str_casefold)) {
2828                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2829                         result = TRUE;
2830                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2831                                                       match_start, match_end, NULL);
2832                         g_free (found_text);
2833                 }
2834                 g_free (range_subtext);
2835                 if (result)
2836                         break;
2837         }
2838         g_free (str_casefold);
2839         g_free (range_text);
2840         g_free (range_casefold);
2841
2842         return result;
2843 }
2844
2845
2846 static void 
2847 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2848                                             ModestMsgEditWindow *window)
2849 {
2850         gchar *current_search = NULL;
2851         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2852         gboolean result;
2853         GtkTextIter selection_start, selection_end;
2854         GtkTextIter match_start, match_end;
2855         gboolean continue_search = FALSE;
2856
2857         if (message_is_empty (window)) {
2858                 g_free (priv->last_search);
2859                 priv->last_search = NULL;
2860                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2861                 return;
2862         }
2863
2864         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
2865         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2866                 g_free (current_search);
2867                 g_free (priv->last_search);
2868                 priv->last_search = NULL;
2869                 /* Information banner about empty search */
2870                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2871                 return;
2872         }
2873
2874         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2875                 continue_search = TRUE;
2876         } else {
2877                 g_free (priv->last_search);
2878                 priv->last_search = g_strdup (current_search);
2879         }
2880
2881         if (continue_search) {
2882                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2883                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
2884                                                                    &match_start, &match_end);
2885                 if (!result)
2886                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
2887         } else {
2888                 GtkTextIter buffer_start;
2889                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2890                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
2891                                                                    &match_start, &match_end);
2892                 if (!result)
2893                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
2894         }
2895
2896         /* Mark as selected the string found in search */
2897         if (result) {
2898                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
2899                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
2900         } else {
2901                 g_free (priv->last_search);
2902                 priv->last_search = NULL;
2903         }
2904         g_free (current_search);
2905 }
2906
2907 static void
2908 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
2909                                            ModestMsgEditWindow *window)
2910 {
2911         GtkToggleAction *toggle;
2912         ModestWindowPrivate *parent_priv;
2913         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2914
2915         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
2916         gtk_toggle_action_set_active (toggle, FALSE);
2917 }
2918
2919
2920 static void 
2921 update_paste_dimming (ModestMsgEditWindow *window)
2922 {
2923         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2924         GtkAction *action = NULL;
2925         GtkClipboard *clipboard = NULL;
2926         ModestEmailClipboard *e_clipboard;
2927         GtkWidget *focused;
2928         gboolean active;
2929
2930         focused = gtk_window_get_focus (GTK_WINDOW (window));
2931
2932         e_clipboard = modest_runtime_get_email_clipboard ();
2933         if (!modest_email_clipboard_cleared (e_clipboard)) {
2934                 active = TRUE;
2935         } else {
2936                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2937                 active = gtk_clipboard_wait_is_text_available (clipboard);
2938         }
2939
2940         if (active) {
2941                 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
2942                         active = FALSE;
2943         }
2944
2945         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
2946         gtk_action_set_sensitive (action, active);
2947
2948 }
2949
2950 static void 
2951 update_select_all_dimming (ModestMsgEditWindow *window)
2952 {
2953         GtkWidget *focused;
2954         gboolean dimmed = FALSE;
2955         GtkAction *action;
2956         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2957
2958         focused = gtk_window_get_focus (GTK_WINDOW (window));
2959         if (GTK_IS_ENTRY (focused)) {
2960                 const gchar *current_text;
2961                 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
2962                 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
2963         } else if (GTK_IS_TEXT_VIEW (focused)) {
2964                 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
2965                 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
2966         } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
2967                 dimmed = FALSE;
2968         }
2969         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
2970         gtk_action_set_sensitive (action, !dimmed);
2971 }
2972
2973 static void 
2974 update_zoom_dimming (ModestMsgEditWindow *window)
2975 {
2976         GtkWidget *focused;
2977         gboolean dimmed = FALSE;
2978         GtkAction *action;
2979         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2980
2981         focused = gtk_window_get_focus (GTK_WINDOW (window));
2982         dimmed = ! WP_IS_TEXT_VIEW (focused);
2983         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
2984         gtk_action_set_sensitive (action, !dimmed);
2985 }
2986
2987 static void
2988 edit_menu_activated (GtkAction *action,
2989                      gpointer userdata)
2990 {
2991         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
2992
2993         update_select_all_dimming (window);
2994         update_paste_dimming (window);
2995 }
2996 static void
2997 view_menu_activated (GtkAction *action,
2998                      gpointer userdata)
2999 {
3000         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3001
3002         update_zoom_dimming (window);
3003 }
3004
3005 gboolean 
3006 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3007 {
3008         ModestMsgEditWindowPrivate *priv;
3009
3010         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3011         return priv->sent;
3012 }
3013
3014 void 
3015 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3016                                  gboolean sent)
3017 {
3018         ModestMsgEditWindowPrivate *priv;
3019
3020         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3021         priv->sent = sent;
3022 }
3023
3024
3025 void            
3026 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3027                                   TnyMsg *draft)
3028 {
3029         ModestMsgEditWindowPrivate *priv;
3030         TnyHeader *header = NULL;
3031
3032         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3033         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3034
3035         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3036         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3037
3038         if (priv->draft_msg != NULL) {
3039                 header = tny_msg_get_header (priv->draft_msg);
3040                 if (TNY_IS_HEADER (header)) {
3041                         modest_window_mgr_unregister_header (mgr, header);
3042                 }
3043                 g_object_unref (priv->draft_msg);
3044         }
3045
3046         if (draft != NULL) {
3047                 g_object_ref (draft);
3048                 header = tny_msg_get_header (draft);
3049                 if (TNY_IS_HEADER (header))
3050                         modest_window_mgr_register_header (mgr, header);
3051         }
3052
3053         priv->draft_msg = draft;
3054 }
3055
3056 static void  
3057 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3058                        GtkTextIter *start, GtkTextIter *end,
3059                        gpointer userdata)
3060 {
3061         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3062         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3063         gchar *tag_name;
3064
3065         if (tag == NULL+13) return;
3066         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3067         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3068                 replace_with_attachments (window, priv->attachments);
3069         }
3070 }
3071
3072 void                    
3073 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3074                                  TnyMimePart *part)
3075 {
3076         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3077
3078         g_return_if_fail (TNY_IS_MIME_PART (part));
3079         priv->attachments = g_list_prepend (priv->attachments, part);
3080         g_object_ref (part);
3081         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3082         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3083         gtk_widget_show_all (priv->attachments_caption);
3084         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3085 }