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