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