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