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