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