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