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