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