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