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