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