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