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