2007-06-20 Murray Cumming <murrayc@murrayc-desktop>
[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         GSList *uris = NULL;
1482         GSList *uri_node;
1483         
1484         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1485         
1486         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1487         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1488
1489         response = gtk_dialog_run (GTK_DIALOG (dialog));
1490         switch (response) {
1491         case GTK_RESPONSE_OK:
1492                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1493                 break;
1494         default:
1495                 break;
1496         }
1497         gtk_widget_destroy (dialog);
1498
1499         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1500                 const gchar *uri;
1501                 GnomeVFSHandle *handle = NULL;
1502                 GnomeVFSResult result;
1503
1504                 uri = (const gchar *) uri_node->data;
1505                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1506                 if (result == GNOME_VFS_OK) {
1507                         TnyMimePart *mime_part;
1508                         TnyStream *stream;
1509                         const gchar *mime_type = NULL;
1510                         gchar *basename;
1511                         gchar *filename;
1512                         gchar *content_id;
1513                         GnomeVFSFileInfo info;
1514
1515                         filename = g_filename_from_uri (uri, NULL, NULL);
1516                         
1517                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
1518                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1519                         mime_part = tny_platform_factory_new_mime_part
1520                                 (modest_runtime_get_platform_factory ());
1521                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1522                         
1523                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1524                         
1525                         content_id = g_strdup_printf ("%d", priv->last_cid);
1526                         tny_mime_part_set_content_id (mime_part, content_id);
1527                         g_free (content_id);
1528                         priv->last_cid++;
1529                         
1530                         basename = g_path_get_basename (filename);
1531                         tny_mime_part_set_filename (mime_part, basename);
1532                         g_free (basename);
1533                         
1534                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1535                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1536                                                                 mime_part);
1537                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1538                         gtk_widget_show_all (priv->attachments_caption);
1539                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1540                         g_free (filename);
1541
1542                 } 
1543         }
1544         g_slist_foreach (uris, (GFunc) g_free, NULL);
1545         g_slist_free (uris);
1546 }
1547
1548 void
1549 modest_msg_edit_window_attach_file_noninteractive (
1550                 ModestMsgEditWindow *window,
1551                 const gchar *file_uri)
1552 {
1553         
1554         ModestMsgEditWindowPrivate *priv;
1555         
1556         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1557
1558         if (file_uri) {
1559                 gint file_id = 0;
1560                 
1561                 /* TODO: We should probably try to use only the URI,
1562                  * instead of using a filename.
1563                  */
1564                 gchar* filename = g_filename_from_uri (file_uri, NULL, NULL);
1565                 if (!filename) {
1566                         g_warning("%s: g_filename_from_uri(%s) failed.\n", __FUNCTION__, file_uri);
1567                 }
1568
1569                 file_id = g_open (filename, O_RDONLY, 0);
1570                 if (file_id != -1) {
1571                         TnyMimePart *mime_part;
1572                         TnyStream *stream;
1573                         const gchar *mime_type;
1574                         gchar *basename;
1575                         gchar *content_id;
1576                         
1577                         mime_type = gnome_vfs_get_file_mime_type_fast (filename, NULL);
1578                         mime_part = tny_platform_factory_new_mime_part
1579                                 (modest_runtime_get_platform_factory ());
1580                         stream = TNY_STREAM (tny_fs_stream_new (file_id));
1581                         
1582                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1583                         
1584                         content_id = g_strdup_printf ("%d", priv->last_cid);
1585                         tny_mime_part_set_content_id (mime_part, content_id);
1586                         g_free (content_id);
1587                         priv->last_cid++;
1588                         
1589                         basename = g_path_get_basename (filename);
1590                         tny_mime_part_set_filename (mime_part, basename);
1591                         g_free (basename);
1592                         
1593                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1594                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1595                                                                 mime_part);
1596                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1597                         gtk_widget_show_all (priv->attachments_caption);
1598                 } else if (file_id == -1) {
1599                         close (file_id);
1600                         g_warning("file to be attached does not exist: %s", filename);
1601                 }
1602
1603                 g_free (filename);
1604         }
1605 }
1606
1607 void
1608 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1609                                           GList *att_list)
1610 {
1611         ModestMsgEditWindowPrivate *priv;
1612         gboolean clean_list = FALSE;
1613
1614         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1615         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1616
1617         if (att_list == NULL) {
1618                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1619                 clean_list = TRUE;
1620         }
1621
1622         if (att_list == NULL) {
1623                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1624         } else {
1625                 GtkWidget *confirmation_dialog = NULL;
1626                 gboolean dialog_response;
1627                 GList *node;
1628                 gchar *message = NULL;
1629                 const gchar *filename = NULL;
1630
1631                 if (att_list->next == NULL) {
1632                         filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1633                 } else {
1634                         filename = "";
1635                 }
1636                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1637                                                     att_list->next == NULL), filename);
1638                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1639                 g_free (message);
1640                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1641                 gtk_widget_destroy (confirmation_dialog);
1642                 if (!dialog_response) {
1643                         if (clean_list)
1644                                 g_list_free (att_list);
1645                         return;
1646                 }
1647                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1648
1649                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1650                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1651                         const gchar *att_id;
1652                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1653
1654                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1655                                                                    mime_part);
1656                         if (priv->attachments == NULL)
1657                                 gtk_widget_hide (priv->attachments_caption);
1658                         att_id = tny_mime_part_get_content_id (mime_part);
1659                         if (att_id != NULL)
1660                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1661                                                                  att_id);
1662                         g_object_unref (mime_part);
1663                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1664                 }
1665         }
1666
1667         if (clean_list)
1668                 g_list_free (att_list);
1669 }
1670
1671 static void
1672 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1673                                             gpointer userdata)
1674 {
1675         ModestMsgEditWindowPrivate *priv;
1676         GdkColor *new_color;
1677         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1678         
1679 #ifdef MODEST_HILDON_VERSION_0  
1680         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1681 #else 
1682         GdkColor col;
1683         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1684         new_color = &col;
1685 #endif /*MODEST_HILDON_VERSION_0*/
1686
1687         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1688         
1689         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1690
1691 }
1692
1693 static void
1694 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1695                                     gpointer userdata)
1696 {
1697         ModestMsgEditWindowPrivate *priv;
1698         gint new_size_index;
1699         ModestMsgEditWindow *window;
1700         GtkWidget *label;
1701         
1702         window = MODEST_MSG_EDIT_WINDOW (userdata);
1703         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1704         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1705
1706         if (gtk_check_menu_item_get_active (menu_item)) {
1707                 gchar *markup;
1708                 WPTextBufferFormat format;
1709
1710                 memset (&format, 0, sizeof (format));
1711                 wp_text_buffer_get_current_state (WP_TEXT_BUFFER (priv->text_buffer), &format);
1712
1713                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1714                 
1715                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1716                 format.cs.font_size = TRUE;
1717                 format.cs.text_position = TRUE;
1718                 format.cs.font = TRUE;
1719                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1720                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format);
1721
1722 /*              if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, */
1723 /*                                                 (gpointer) wp_get_font_size_index (new_size_index, 12))) */
1724 /*                      wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); */
1725                 
1726                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1727                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1728                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1729                 g_free (markup);
1730         }
1731 }
1732
1733 static void
1734 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1735                                     gpointer userdata)
1736 {
1737         ModestMsgEditWindowPrivate *priv;
1738         gint new_font_index;
1739         ModestMsgEditWindow *window;
1740         GtkWidget *label;
1741         
1742         window = MODEST_MSG_EDIT_WINDOW (userdata);
1743         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1744         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1745
1746         if (gtk_check_menu_item_get_active (menu_item)) {
1747                 gchar *markup;
1748
1749                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1750                 
1751                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1752
1753                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1754                                                    (gpointer) new_font_index))
1755                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1756                 
1757                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1758                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1759                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1760                 g_free (markup);
1761         }
1762 }
1763
1764 static void
1765 modest_msg_edit_window_set_zoom (ModestWindow *window,
1766                                  gdouble zoom)
1767 {
1768         ModestMsgEditWindowPrivate *priv;
1769      
1770         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1771
1772         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1773         priv->zoom_level = zoom;
1774         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1775 }
1776
1777 static gdouble
1778 modest_msg_edit_window_get_zoom (ModestWindow *window)
1779 {
1780         ModestMsgEditWindowPrivate *priv;
1781      
1782         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1783
1784         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1785         return priv->zoom_level;
1786 }
1787
1788 static gboolean
1789 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1790 {
1791         ModestWindowPrivate *parent_priv;
1792         GtkRadioAction *zoom_radio_action;
1793         GSList *group, *node;
1794
1795         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1796         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1797                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1798
1799         group = gtk_radio_action_get_group (zoom_radio_action);
1800
1801         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1802                 hildon_banner_show_information (NULL, NULL, _("ckct_ib_max_zoom_level_reached"));
1803                 return FALSE;
1804         }
1805
1806         for (node = group; node != NULL; node = g_slist_next (node)) {
1807                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1808                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1809                         return TRUE;
1810                 }
1811         }
1812         return FALSE;
1813 }
1814
1815 static gboolean
1816 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1817 {
1818         ModestWindowPrivate *parent_priv;
1819         GtkRadioAction *zoom_radio_action;
1820         GSList *group, *node;
1821
1822         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1823         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1824                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1825
1826         group = gtk_radio_action_get_group (zoom_radio_action);
1827
1828         for (node = group; node != NULL; node = g_slist_next (node)) {
1829                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1830                         if (node->next != NULL) {
1831                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1832                                 return TRUE;
1833                         } else
1834                                 hildon_banner_show_information (NULL, NULL, _("ckct_ib_min_zoom_level_reached"));
1835                         break;
1836                 }
1837         }
1838         return FALSE;
1839 }
1840
1841 static gboolean
1842 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1843 {
1844         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1845                 ModestWindowPrivate *parent_priv;
1846                 ModestWindowMgr *mgr;
1847                 gboolean is_fullscreen;
1848                 GtkAction *fs_toggle_action;
1849                 gboolean active;
1850
1851                 mgr = modest_runtime_get_window_mgr ();
1852                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1853
1854                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1855                 
1856                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1857                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1858                 if (is_fullscreen != active)
1859                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1860         }
1861
1862         return FALSE;
1863
1864 }
1865
1866 void
1867 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1868 {
1869         ModestWindowPrivate *parent_priv;
1870         GtkAction *fs_toggle_action;
1871         gboolean active;
1872
1873         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1874
1875         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1876         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1877         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1878 }
1879
1880 void
1881 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1882                                 gboolean show)
1883 {
1884         ModestMsgEditWindowPrivate *priv = NULL;
1885         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1886
1887         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1888         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1889         if (show)
1890                 gtk_widget_show (priv->cc_caption);
1891         else
1892                 gtk_widget_hide (priv->cc_caption);
1893         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
1894 }
1895
1896 void
1897 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1898                                  gboolean show)
1899 {
1900         ModestMsgEditWindowPrivate *priv = NULL;
1901         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1902
1903         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1904         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1905         if (show)
1906                 gtk_widget_show (priv->bcc_caption);
1907         else
1908                 gtk_widget_hide (priv->bcc_caption);
1909         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
1910 }
1911
1912 static void
1913 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
1914                                          ModestRecptEditor *editor)
1915 {
1916         ModestMsgEditWindowPrivate *priv;
1917
1918         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1919         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
1920         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1921
1922         if (editor == NULL) {
1923                 GtkWidget *view_focus;
1924                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
1925
1926                 /* This code should be kept in sync with ModestRecptEditor. The
1927                    textview inside the recpt editor is the one that really gets the
1928                    focus. As it's inside a scrolled window, and this one inside the
1929                    hbox recpt editor inherits from, we'll need to go up in the 
1930                    hierarchy to know if the text view is part of the recpt editor
1931                    or if it's a different text entry */
1932
1933                 if (gtk_widget_get_parent (view_focus)) {
1934                         GtkWidget *first_parent;
1935
1936                         first_parent = gtk_widget_get_parent (view_focus);
1937                         if (gtk_widget_get_parent (first_parent) && 
1938                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
1939                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
1940                         }
1941                 }
1942
1943                 if (editor == NULL)
1944                         editor = MODEST_RECPT_EDITOR (priv->to_field);
1945
1946         }
1947
1948         modest_address_book_select_addresses (editor);
1949
1950 }
1951
1952 void
1953 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
1954 {
1955         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1956
1957         modest_msg_edit_window_open_addressbook (window, NULL);
1958 }
1959
1960 static void
1961 modest_msg_edit_window_show_toolbar (ModestWindow *self,
1962                                      gboolean show_toolbar)
1963 {
1964         ModestWindowPrivate *parent_priv;
1965         
1966         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1967         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1968
1969         /* FIXME: we can not just use the code of
1970            modest_msg_edit_window_setup_toolbar because it has a
1971            mixture of both initialization and creation code. */
1972
1973         if (show_toolbar)
1974                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1975         else
1976                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1977 }
1978
1979 void
1980 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
1981                                            TnyHeaderFlags priority_flags)
1982 {
1983         ModestMsgEditWindowPrivate *priv;
1984         ModestWindowPrivate *parent_priv;
1985
1986         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1987
1988         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1989         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1990         priority_flags = priority_flags & (TNY_HEADER_FLAG_HIGH_PRIORITY);
1991
1992         if (priv->priority_flags != priority_flags) {
1993                 GtkAction *priority_action = NULL;
1994
1995                 priv->priority_flags = priority_flags;
1996
1997                 switch (priority_flags) {
1998                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
1999                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2000                         gtk_widget_show (priv->priority_icon);
2001                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2002                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2003                         break;
2004                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2005                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2006                         gtk_widget_show (priv->priority_icon);
2007                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2008                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2009                         break;
2010                 default:
2011                         gtk_widget_hide (priv->priority_icon);
2012                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2013                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2014                         break;
2015                 }
2016                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2017                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2018         }
2019 }
2020
2021 void
2022 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2023                                         gint file_format)
2024 {
2025         ModestMsgEditWindowPrivate *priv;
2026         gint current_format;
2027
2028         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2029
2030         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2031
2032         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2033                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2034
2035         if (current_format != file_format) {
2036                 switch (file_format) {
2037                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2038                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2039                         break;
2040                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2041                 {
2042                         GtkWidget *dialog;
2043                         gint response;
2044                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2045                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2046                         gtk_widget_destroy (dialog);
2047                         if (response == GTK_RESPONSE_OK)
2048                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2049                 }
2050                         break;
2051                 }
2052                 update_dimmed (window);
2053         }
2054 }
2055
2056 void
2057 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2058 {
2059         GtkWidget *dialog;
2060         ModestMsgEditWindowPrivate *priv;
2061         WPTextBufferFormat oldfmt, fmt;
2062         gint old_position = 0;
2063         gint response = 0;
2064         gint position = 0;
2065         gint font_size;
2066         GdkColor *color = NULL;
2067         gboolean bold, bold_set, italic, italic_set;
2068         gboolean underline, underline_set;
2069         gboolean strikethrough, strikethrough_set;
2070         gboolean position_set;
2071         gboolean font_size_set, font_set, color_set;
2072         gchar *font_name;
2073
2074         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2075         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2076         
2077         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2078
2079         /* First we get the currently selected font information */
2080         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2081         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2082
2083         switch (oldfmt.text_position) {
2084         case TEXT_POSITION_NORMAL:
2085                 old_position = 0;
2086                 break;
2087         case TEXT_POSITION_SUPERSCRIPT:
2088                 old_position = 1;
2089                 break;
2090         default:
2091                 old_position = -1;
2092                 break;
2093         }
2094
2095         g_object_set (G_OBJECT (dialog),
2096                       "bold", oldfmt.bold != FALSE,
2097                       "bold-set", !oldfmt.cs.bold,
2098                       "underline", oldfmt.underline != FALSE,
2099                       "underline-set", !oldfmt.cs.underline,
2100                       "italic", oldfmt.italic != FALSE,
2101                       "italic-set", !oldfmt.cs.italic,
2102                       "strikethrough", oldfmt.strikethrough != FALSE,
2103                       "strikethrough-set", !oldfmt.cs.strikethrough,
2104                       "color", &oldfmt.color,
2105                       "color-set", !oldfmt.cs.color,
2106                       "size", wp_font_size[oldfmt.font_size],
2107                       "size-set", !oldfmt.cs.font_size,
2108                       "position", old_position,
2109                       "position-set", !oldfmt.cs.text_position,
2110                       "family", wp_get_font_name (oldfmt.font),
2111                       "family-set", !oldfmt.cs.font,
2112                       NULL);
2113
2114         gtk_widget_show_all (dialog);
2115         response = gtk_dialog_run (GTK_DIALOG (dialog));
2116         if (response == GTK_RESPONSE_OK) {
2117
2118                 g_object_get( dialog,
2119                               "bold", &bold,
2120                               "bold-set", &bold_set,
2121                               "underline", &underline,
2122                               "underline-set", &underline_set,
2123                               "italic", &italic,
2124                               "italic-set", &italic_set,
2125                               "strikethrough", &strikethrough,
2126                               "strikethrough-set", &strikethrough_set,
2127                               "color", &color,
2128                               "color-set", &color_set,
2129                               "size", &font_size,
2130                               "size-set", &font_size_set,
2131                               "family", &font_name,
2132                               "family-set", &font_set,
2133                               "position", &position,
2134                               "position-set", &position_set,
2135                               NULL );
2136                 
2137         }       
2138
2139         if (response == GTK_RESPONSE_OK) {
2140                 memset(&fmt, 0, sizeof(fmt));
2141                 if (bold_set) {
2142                         fmt.bold = bold;
2143                         fmt.cs.bold = TRUE;
2144                 }
2145                 if (italic_set) {
2146                         fmt.italic = italic;
2147                         fmt.cs.italic = TRUE;
2148                 }
2149                 if (underline_set) {
2150                         fmt.underline = underline;
2151                         fmt.cs.underline = TRUE;
2152                 }
2153                 if (strikethrough_set) {
2154                         fmt.strikethrough = strikethrough;
2155                         fmt.cs.strikethrough = TRUE;
2156                 }
2157                 if (position_set) {
2158                         fmt.text_position =
2159                                 ( position == 0 )
2160                                 ? TEXT_POSITION_NORMAL
2161                                 : ( ( position == 1 )
2162                                     ? TEXT_POSITION_SUPERSCRIPT
2163                                     : TEXT_POSITION_SUBSCRIPT );
2164                         fmt.cs.text_position = TRUE;
2165                 }
2166                 if (color_set) {
2167                         fmt.color = *color;
2168                         fmt.cs.color = TRUE;
2169                 }
2170                 if (font_set) {
2171                         fmt.font = wp_get_font_index(font_name,
2172                                                      DEFAULT_FONT);
2173                         fmt.cs.font = TRUE;
2174                 }
2175                 g_free(font_name);
2176                 if (font_size_set) {
2177                         fmt.font_size = wp_get_font_size_index(
2178                                 font_size, DEFAULT_FONT_SIZE);
2179                         fmt.cs.font_size = TRUE;
2180                 }
2181                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2182         }
2183         gtk_widget_destroy (dialog);
2184         
2185         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2186 }
2187
2188 void
2189 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2190 {
2191         ModestMsgEditWindowPrivate *priv;
2192
2193         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2194         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2195         
2196         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2197
2198         update_dimmed (window);
2199
2200 }
2201
2202 static void
2203 update_dimmed (ModestMsgEditWindow *window)
2204 {
2205         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2206         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2207         GtkAction *action;
2208         GtkWidget *widget;
2209         gboolean rich_text;
2210         gboolean editor_focused;
2211
2212         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2213         editor_focused = gtk_widget_is_focus (priv->msg_body);
2214
2215         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2216         gtk_action_set_sensitive (action, rich_text && editor_focused);
2217         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2218         gtk_action_set_sensitive (action, rich_text && editor_focused);
2219         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2220         gtk_action_set_sensitive (action, rich_text && editor_focused);
2221         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2222         gtk_action_set_sensitive (action, rich_text && editor_focused);
2223         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2224         gtk_action_set_sensitive (action, rich_text && editor_focused);
2225         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2226         gtk_action_set_sensitive (action, rich_text && editor_focused);
2227         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2228         gtk_action_set_sensitive (action, rich_text && editor_focused);
2229         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2230         gtk_action_set_sensitive (action, rich_text && editor_focused);
2231         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2232         gtk_action_set_sensitive (action, rich_text && editor_focused);
2233         widget = priv->font_color_button;
2234         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2235         widget = priv->font_size_toolitem;
2236         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2237         widget = priv->font_face_toolitem;
2238         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2239 }
2240
2241 static void
2242 setup_insensitive_handlers (ModestMsgEditWindow *window)
2243 {
2244         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2245         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2246         GtkWidget *widget;
2247
2248         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2249         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2250         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2251         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2252
2253         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
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/BulletedListMenu");
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/FormatMenu/AlignmentMenu");
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, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
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, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2262         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2263         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2264         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2265         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2266         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2267         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2268         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2269         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2270         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2271         widget = priv->font_color_button;
2272         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2273         widget = priv->font_size_toolitem;
2274         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2275         widget = priv->font_face_toolitem;
2276         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2277
2278 }
2279
2280 static void  
2281 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2282 {
2283         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2284         GtkAction *action;
2285
2286         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2287         gtk_action_set_sensitive (action, can_undo);
2288 }
2289
2290 static void
2291 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2292 {
2293         GtkTextIter iter;
2294         GtkTextIter match_start, match_end;
2295
2296         if (image_id == NULL)
2297                 return;
2298
2299         gtk_text_buffer_get_start_iter (buffer, &iter);
2300
2301         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2302                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2303                 GSList *node;
2304                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2305                         GtkTextTag *tag = (GtkTextTag *) node->data;
2306                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2307                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2308                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2309                                         gint offset;
2310                                         offset = gtk_text_iter_get_offset (&match_start);
2311                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2312                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2313                                 }
2314                         }
2315                 }
2316                 gtk_text_iter_forward_char (&iter);
2317         }
2318 }
2319
2320 static void
2321 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2322 {
2323         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2324         GtkTextIter real_start, real_end;
2325         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2326
2327         if (gtk_text_iter_compare (start, end) > 0) {
2328                 real_start = *end;
2329                 real_end = *start;
2330         } else {
2331                 real_start = *start;
2332                 real_end = *end;
2333         }
2334         do {
2335                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2336                 GSList *node;
2337                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2338                         GtkTextTag *tag = (GtkTextTag *) node->data;
2339                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2340                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2341
2342                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2343                                                                                  image_id);
2344                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2345                         }
2346                 }
2347         } while (gtk_text_iter_forward_char (&real_start)&&
2348                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2349 }
2350
2351 static gboolean
2352 msg_body_focus (GtkWidget *focus,
2353                 GdkEventFocus *event,
2354                 gpointer userdata)
2355 {
2356         
2357         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2358         return FALSE;
2359 }
2360
2361 static void
2362 recpt_field_changed (GtkTextBuffer *buffer,
2363                   ModestMsgEditWindow *editor)
2364 {
2365         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2366         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2367         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2368         gboolean dim = FALSE;
2369         GtkAction *action;
2370
2371         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2372         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2373         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2374         
2375         dim = ((gtk_text_buffer_get_char_count (to_buffer) + 
2376                 gtk_text_buffer_get_char_count (cc_buffer) +
2377                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2378                         
2379         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2380         gtk_action_set_sensitive (action, !dim);
2381         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2382         gtk_action_set_sensitive (action, !dim);
2383 }
2384
2385 static void  
2386 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2387 {
2388         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2389 }
2390
2391 static void
2392 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2393 {
2394         gboolean rich_text, editor_focused;
2395
2396         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2397         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2398         editor_focused = gtk_widget_is_focus (priv->msg_body);
2399
2400         if (!rich_text)
2401                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2402         else if (!editor_focused)
2403                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2404 }
2405
2406 static void
2407 reset_modified (ModestMsgEditWindow *editor)
2408 {
2409         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2410         GtkTextBuffer *buffer;
2411
2412         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2413         gtk_text_buffer_set_modified (buffer, FALSE);
2414         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2415         gtk_text_buffer_set_modified (buffer, FALSE);
2416         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2417         gtk_text_buffer_set_modified (buffer, FALSE);
2418         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2419 }
2420
2421 static gboolean
2422 is_modified (ModestMsgEditWindow *editor)
2423 {
2424         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2425         GtkTextBuffer *buffer;
2426
2427         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2428         if (gtk_text_buffer_get_modified (buffer))
2429                 return TRUE;
2430         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2431         if (gtk_text_buffer_get_modified (buffer))
2432                 return TRUE;
2433         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2434         if (gtk_text_buffer_get_modified (buffer))
2435                 return TRUE;
2436         if (gtk_text_buffer_get_modified (priv->text_buffer))
2437                 return TRUE;
2438
2439         return FALSE;
2440 }
2441
2442 gboolean
2443 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2444 {
2445         ModestMsgEditWindowPrivate *priv = NULL;
2446
2447         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2448         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2449
2450         /* check if there's no recipient added */
2451         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2452             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2453             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2454                 /* no recipient contents, then select contacts */
2455                 modest_msg_edit_window_open_addressbook (window, NULL);
2456                 return FALSE;
2457         }
2458
2459         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2460                 return FALSE;
2461         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2462                 return FALSE;
2463         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2464                 return FALSE;
2465
2466         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2467
2468         return TRUE;
2469
2470 }
2471
2472 static void
2473 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2474                                                ModestMsgEditWindow *window)
2475 {
2476         modest_msg_edit_window_attach_file (window);
2477 }
2478
2479 static void
2480 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2481                                                GdkEvent *event,
2482                                                ModestMsgEditWindow *window)
2483 {
2484         ModestWindowPrivate *parent_priv;
2485         GtkAction *action;
2486         gchar *selection;
2487         GtkWidget *focused;
2488
2489         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2490         selection = gtk_clipboard_wait_for_text (clipboard);
2491         focused = gtk_window_get_focus (GTK_WINDOW (window));
2492
2493         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2494         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2495         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2496         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2497 }
2498
2499 static void 
2500 update_window_title (ModestMsgEditWindow *window)
2501 {
2502         ModestMsgEditWindowPrivate *priv = NULL;
2503         const gchar *subject;
2504
2505         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2506         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2507         if (subject == NULL || subject[0] == '\0')
2508                 subject = _("mail_va_new_email");
2509
2510         gtk_window_set_title (GTK_WINDOW (window), subject);
2511
2512 }
2513
2514 static void  
2515 subject_field_changed (GtkEditable *editable, 
2516                        ModestMsgEditWindow *window)
2517 {
2518         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2519         update_window_title (window);
2520         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2521 }
2522
2523 void
2524 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2525                                             gboolean show)
2526 {
2527         ModestMsgEditWindowPrivate *priv = NULL;
2528
2529         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2530         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2531
2532         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2533         if (show) {
2534                 gtk_widget_show_all (priv->find_toolbar);
2535                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2536         } else {
2537                 gtk_widget_hide_all (priv->find_toolbar);
2538                 gtk_widget_grab_focus (priv->msg_body);
2539         }
2540     
2541 }
2542
2543 static void 
2544 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2545                                             ModestMsgEditWindow *window)
2546 {
2547         gchar *current_search = NULL;
2548         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2549         gboolean result;
2550         GtkTextIter selection_start, selection_end;
2551         GtkTextIter match_start, match_end;
2552
2553         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
2554         if ((current_search == NULL) && (strcmp (current_search, "") == 0)) {
2555                 g_free (current_search);
2556                 return;
2557         }
2558
2559         gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2560         result = gtk_text_iter_forward_search (&selection_end, current_search, GTK_TEXT_SEARCH_VISIBLE_ONLY, &match_start, &match_end, NULL);
2561         if (!result) {
2562                 GtkTextIter buffer_start;
2563                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2564                 result = gtk_text_iter_forward_search (&buffer_start, current_search, GTK_TEXT_SEARCH_VISIBLE_ONLY, &match_start, &match_end, &selection_start);
2565         }
2566         if (result) {
2567                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
2568                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
2569         } else {
2570                 /* TODO: warning about non succesful search */
2571         }
2572         g_free (current_search);
2573 }
2574
2575 static void
2576 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
2577                                            ModestMsgEditWindow *window)
2578 {
2579         GtkToggleAction *toggle;
2580         ModestWindowPrivate *parent_priv;
2581         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2582
2583         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
2584         gtk_toggle_action_set_active (toggle, FALSE);
2585 }
2586
2587