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