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