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