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