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