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