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