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