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