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