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