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