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