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