* Implement optimizations on DimmingRules management.
[modest] / src / maemo / modest-msg-edit-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <fcntl.h>
33 #include <glib/gstdio.h>
34 #include <string.h>
35 #include <tny-account-store.h>
36 #include <tny-fs-stream.h>
37 #include <tny-vfs-stream.h>
38
39 #include <config.h>
40
41 #include <modest-account-mgr.h>
42 #include <modest-account-mgr-helpers.h>
43
44 #include <widgets/modest-msg-edit-window.h>
45 #include <widgets/modest-combo-box.h>
46 #include <widgets/modest-recpt-editor.h>
47 #include <widgets/modest-attachments-view.h>
48
49 #include <modest-runtime.h>
50
51 #include "modest-platform.h"
52 #include "modest-icon-names.h"
53 #include "modest-widget-memory.h"
54 #include "modest-window-priv.h"
55 #include "modest-mail-operation.h"
56 #include "modest-tny-platform-factory.h"
57 #include "modest-tny-msg.h"
58 #include "modest-tny-folder.h"
59 #include "modest-address-book.h"
60 #include "modest-text-utils.h"
61 #include <tny-simple-list.h>
62 #include <wptextview.h>
63 #include <wptextbuffer.h>
64 #include "modest-scroll-area.h"
65
66 #include "modest-hildon-includes.h"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-color-chooser.h>
69 #endif
70 #include "widgets/modest-msg-edit-window-ui.h"
71 #ifdef MODEST_HAVE_HILDON0_WIDGETS
72 #include <libgnomevfs/gnome-vfs-mime-utils.h>
73 #else
74 #include <libgnomevfs/gnome-vfs-mime.h>
75 #endif
76 #include "modest-maemo-utils.h"
77
78
79 #define DEFAULT_FONT_SIZE 3
80 #define DEFAULT_FONT 2
81 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
82 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
83 #define DEFAULT_MAIN_VBOX_SPACING 6
84 #define SUBJECT_MAX_LENGTH 1000
85 #define IMAGE_MAX_WIDTH 560
86 #define DEFAULT_FONT_SCALE 1.5
87
88 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
89 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
90 static void  modest_msg_edit_window_finalize     (GObject *obj);
91
92 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
93 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
94 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
95 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
96 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
97 static void  reset_modified (ModestMsgEditWindow *editor);
98
99 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
100 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
101 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
102 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
103                                     GtkTextIter *start, GtkTextIter *end,
104                                     gpointer userdata);
105 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
106 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
107 static void  subject_field_insert_text (GtkEditable *editable, 
108                                         gchar *new_text,
109                                         gint new_text_length,
110                                         gint *position,
111                                         ModestMsgEditWindow *window);
112 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
113                                                          gpointer userdata);
114 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
115                                                  gpointer userdata);
116 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
117                                                  gpointer userdata);
118 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
119 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
120                                                            GdkEventWindowState *event, 
121                                                            gpointer userdata);
122 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
123                                                      ModestRecptEditor *editor);
124 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
125                                                            ModestMsgEditWindow *window);
126
127 /* ModestWindow methods implementation */
128 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
129 static void modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
130 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
131 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
132 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
133 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
134                                                    gboolean show_toolbar);
135 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
136                                                            GdkEvent *event,
137                                                            ModestMsgEditWindow *window);
138 static void update_window_title (ModestMsgEditWindow *window);
139 static void update_dimmed (ModestMsgEditWindow *window);
140 static void update_paste_dimming (ModestMsgEditWindow *window);
141 static void update_copy_cut_dimming (ModestMsgEditWindow *window);
142 static void update_select_all_dimming (ModestMsgEditWindow *window);
143 static void update_zoom_dimming (ModestMsgEditWindow *window);
144
145 /* Find toolbar */
146 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
147                                                         ModestMsgEditWindow *window);
148 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
149                                                        ModestMsgEditWindow *window);
150 static gboolean gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
151                                                           const gchar *str,
152                                                           GtkTextIter *match_start,
153                                                           GtkTextIter *match_end);
154                                                           
155 static void DEBUG_BUFFER (WPTextBuffer *buffer)
156 {
157 #ifdef DEBUG
158         GtkTextIter iter;
159
160         g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
161         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
162         while (!gtk_text_iter_is_end (&iter)) {
163                 GString *output = g_string_new ("");
164                 GSList *toggled_tags;
165                 GSList *node;
166
167                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
168                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
169                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
170                         GtkTextTag *tag = (GtkTextTag *) node->data;
171                         const gchar *name;
172                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
173                         output = g_string_append (output, name);
174                         g_string_append (output, " ");
175                 }
176                 output = g_string_append (output, "] OPENED [ ");
177                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
178                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
179                         GtkTextTag *tag = (GtkTextTag *) node->data;
180                         const gchar *name;
181                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
182                         output = g_string_append (output, name);
183                         g_string_append (output, " ");
184                 }
185                 output = g_string_append (output, "]\n");
186                 g_message ("%s", output->str);
187                 g_string_free (output, TRUE);
188                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
189         }
190         g_message ("END BUFFER");
191 #endif
192 }
193
194
195 /* static gboolean */
196 /* on_key_pressed (GtkWidget *self, */
197 /*              GdkEventKey *event, */
198 /*              gpointer user_data); */
199
200 static void edit_menu_activated (GtkAction *action,
201                                  gpointer userdata);
202 static void view_menu_activated (GtkAction *action,
203                                  gpointer userdata);
204
205 /* list my signals */
206 enum {
207         /* MY_SIGNAL_1, */
208         /* MY_SIGNAL_2, */
209         LAST_SIGNAL
210 };
211
212 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
213 struct _ModestMsgEditWindowPrivate {
214         GtkWidget   *msg_body;
215         GtkWidget   *header_box;
216         
217         ModestPairList *from_field_protos;
218         GtkWidget   *from_field;
219         
220         GtkWidget   *to_field;
221         GtkWidget   *cc_field;
222         GtkWidget   *bcc_field;
223         GtkWidget   *subject_field;
224         GtkWidget   *attachments_view;
225         GtkWidget   *priority_icon;
226         GtkWidget   *add_attachment_button;
227
228         GtkWidget   *cc_caption;
229         GtkWidget   *bcc_caption;
230         gboolean     update_caption_visibility;
231         GtkWidget   *attachments_caption;
232
233         GtkTextBuffer *text_buffer;
234
235         GtkWidget   *font_size_toolitem;
236         GtkWidget   *font_face_toolitem;
237         GtkWidget   *font_color_button;
238         GSList      *font_items_group;
239         GtkWidget   *font_tool_button_label;
240         GSList      *size_items_group;
241         GtkWidget   *size_tool_button_label;
242         
243         GtkWidget   *find_toolbar;
244         gchar       *last_search;
245
246         GtkWidget   *scroll;
247         GtkWidget   *scroll_area;
248         gint        last_vadj_upper;
249
250         gint last_cid;
251         GList *attachments;
252
253         TnyHeaderFlags priority_flags;
254
255         gdouble zoom_level;
256         
257         gulong      clipboard_change_handler_id;
258
259         TnyMsg      *draft_msg;
260         TnyMsg      *outbox_msg;
261         gchar       *msg_uid;
262
263         gboolean    sent;
264 };
265
266 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
267                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
268                                                     ModestMsgEditWindowPrivate))
269 /* globals */
270 static GtkWindowClass *parent_class = NULL;
271
272 /* uncomment the following if you have defined any signals */
273 /* static guint signals[LAST_SIGNAL] = {0}; */
274
275 GType
276 modest_msg_edit_window_get_type (void)
277 {
278         static GType my_type = 0;
279         if (!my_type) {
280                 static const GTypeInfo my_info = {
281                         sizeof(ModestMsgEditWindowClass),
282                         NULL,           /* base init */
283                         NULL,           /* base finalize */
284                         (GClassInitFunc) modest_msg_edit_window_class_init,
285                         NULL,           /* class finalize */
286                         NULL,           /* class data */
287                         sizeof(ModestMsgEditWindow),
288                         1,              /* n_preallocs */
289                         (GInstanceInitFunc) modest_msg_edit_window_init,
290                         NULL
291                 };
292                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
293                                                   "ModestMsgEditWindow",
294                                                   &my_info, 0);
295
296                 wp_text_buffer_library_init ();
297         }
298         return my_type;
299 }
300
301 static void
302 save_state (ModestWindow *self)
303 {
304         modest_widget_memory_save (modest_runtime_get_conf(),
305                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
306 }
307
308
309 static void
310 restore_settings (ModestMsgEditWindow *self)
311 {
312         modest_widget_memory_restore (modest_runtime_get_conf(),
313                                       G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
314 }
315
316
317 static void
318 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
319 {
320         GObjectClass *gobject_class;
321         ModestWindowClass *modest_window_class;
322         gobject_class = (GObjectClass*) klass;
323         modest_window_class = (ModestWindowClass*) klass;
324
325         parent_class            = g_type_class_peek_parent (klass);
326         gobject_class->finalize = modest_msg_edit_window_finalize;
327
328         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
329         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
330         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
331         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
332         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
333         modest_window_class->save_state_func = save_state;
334         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
335
336         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
337 }
338
339 static void
340 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
341 {
342         ModestMsgEditWindowPrivate *priv;
343         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
344
345         priv->msg_body      = NULL;
346         priv->from_field    = NULL;
347         priv->to_field      = NULL;
348         priv->cc_field      = NULL;
349         priv->bcc_field     = NULL;
350         priv->subject_field = NULL;
351         priv->attachments   = NULL;
352         priv->last_cid      = 0;
353         priv->zoom_level    = 1.0;
354
355         priv->cc_caption    = NULL;
356         priv->bcc_caption    = NULL;
357         priv->update_caption_visibility = FALSE;
358
359         priv->priority_flags = 0;
360
361         priv->find_toolbar = NULL;
362         priv->last_search = NULL;
363
364         priv->draft_msg = NULL;
365         priv->outbox_msg = NULL;
366         priv->msg_uid = NULL;
367         priv->clipboard_change_handler_id = 0;
368         priv->sent = FALSE;
369
370         priv->last_vadj_upper = 0;
371 }
372
373
374 /* FIXME: this is a dup from the one in gtk/ */
375
376 /** 
377  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
378  */
379 static ModestPairList*
380 get_transports (void)
381 {
382         GSList *transports = NULL;
383         
384         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
385         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
386                                                              TRUE /* only enabled accounts. */); 
387                                                 
388         GSList *cursor = accounts;
389         while (cursor) {
390                 gchar *account_name = cursor->data;
391                 gchar *from_string  = NULL;
392                 if (account_name) {
393                         from_string = modest_account_mgr_get_from_string (account_mgr,
394                                                                           account_name);
395                 }
396                 
397                 if (from_string && account_name) {
398                         gchar *name = account_name;
399                         ModestPair *pair = modest_pair_new ((gpointer) name,
400                                                 (gpointer) from_string , TRUE);
401                         transports = g_slist_prepend (transports, pair);
402                 }
403                 
404                 cursor = cursor->next;
405         }
406         g_slist_free (accounts); /* only free the accounts, not the elements,
407                                   * because they are used in the pairlist */
408         return transports;
409 }
410
411 void vadj_changed (GtkAdjustment *adj,
412                    ModestMsgEditWindow *window)
413 {
414         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
415
416         GdkRectangle rectangle, cursor_rectangle;
417         GtkTextIter position;
418         gboolean visible;
419         gint cursor_bottom;
420
421         /* We detect if cursor is visible using the full height, not only the center. This
422            seems to work */
423         gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (priv->msg_body), &rectangle);
424         gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer),
425                                           &position,
426                                           gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)));
427         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &position, &cursor_rectangle);
428
429         cursor_bottom = (cursor_rectangle.y + cursor_rectangle.height);
430         visible = (cursor_rectangle.y >= rectangle.y) && (cursor_bottom < (rectangle.y + rectangle.height));
431
432         if (gtk_widget_is_focus (priv->msg_body) && 
433             !visible) {
434                 if (priv->last_vadj_upper != adj->upper) {
435                         GtkTextMark *insert;
436                         
437                         insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
438                         gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (priv->msg_body), 
439                                                       insert, 0.1, FALSE, 0.0, 0.0);
440                 }
441         }
442         priv->last_vadj_upper = adj->upper;
443 }
444
445
446 static void
447 init_window (ModestMsgEditWindow *obj)
448 {
449         GtkWidget *from_caption, *to_caption, *subject_caption;
450         GtkWidget *main_vbox;
451         ModestMsgEditWindowPrivate *priv;
452
453         GtkSizeGroup *size_group;
454         GtkWidget *frame;
455         GtkWidget *subject_box;
456         GtkWidget *attachment_icon;
457         GtkWidget *window_box;
458 #if (GTK_MINOR_VERSION >= 10)
459         GdkAtom deserialize_type;
460 #endif
461         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
462
463         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
464
465         /* Note: This ModestPairList* must exist for as long as the combo
466          * that uses it, because the ModestComboBox uses the ID opaquely, 
467          * so it can't know how to manage its memory. */ 
468         priv->from_field_protos = get_transports ();
469
470         priv->from_field    = modest_combo_box_new (priv->from_field_protos, g_str_equal);
471
472         priv->to_field      = modest_recpt_editor_new ();
473         priv->cc_field      = modest_recpt_editor_new ();
474         priv->bcc_field     = modest_recpt_editor_new ();
475         subject_box = gtk_hbox_new (FALSE, 0);
476         priv->priority_icon = gtk_image_new ();
477         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
478         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
479         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
480         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
481                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
482         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
483         priv->add_attachment_button = gtk_button_new ();
484         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
485         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
486         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
487         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
488         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
489         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
490         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
491         priv->attachments_view = modest_attachments_view_new (NULL);
492         
493         priv->header_box = gtk_vbox_new (FALSE, 0);
494         
495         from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
496         to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
497         priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
498         priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
499         subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
500         priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
501         g_object_unref (size_group);
502
503         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
504         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
505         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
506         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
507         gtk_size_group_add_widget (size_group, priv->subject_field);
508         gtk_size_group_add_widget (size_group, priv->attachments_view);
509         g_object_unref (size_group);
510
511         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
512         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
513         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
514         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
515         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
516         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
517         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
518
519
520         priv->msg_body = wp_text_view_new ();
521         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
522         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
523         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
524         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
525 #if (GTK_MINOR_VERSION >= 10)
526         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), "wp-text-buffer");
527         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
528                                                                        "wp-text-buffer");
529         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
530                                                          deserialize_type, TRUE);
531 #endif
532         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
533
534         priv->find_toolbar = hildon_find_toolbar_new (NULL);
535         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
536
537 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
538
539         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
540                           G_CALLBACK (text_buffer_refresh_attributes), obj);
541         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
542                           G_CALLBACK (text_buffer_can_undo), obj);
543         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
544                           G_CALLBACK (text_buffer_can_redo), obj);
545         g_signal_connect (G_OBJECT (obj), "window-state-event",
546                           G_CALLBACK (modest_msg_edit_window_window_state_event),
547                           NULL);
548         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
549                                 G_CALLBACK (text_buffer_apply_tag), obj);
550         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
551                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
552         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
553                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
554         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
555                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
556
557         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
558                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
559
560         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
561                           G_CALLBACK (msg_body_focus), obj);
562         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
563                           G_CALLBACK (msg_body_focus), obj);
564         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
565                           "changed", G_CALLBACK (recpt_field_changed), obj);
566         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
567                           "changed", G_CALLBACK (recpt_field_changed), obj);
568         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
569                           "changed", G_CALLBACK (recpt_field_changed), obj);
570         recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
571         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
572         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
573
574         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
575         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
576
577         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
578         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
579         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
580         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->scroll), TRUE);
581
582         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
583
584         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
585         frame = gtk_frame_new (NULL);
586         gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
587
588         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
589         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
590         g_signal_connect (G_OBJECT (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll))),
591                           "changed",
592                           G_CALLBACK (vadj_changed),
593                           obj);
594         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
595         
596         window_box = gtk_vbox_new (FALSE, 0);
597         gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
598         gtk_container_add (GTK_CONTAINER(obj), window_box);
599         priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
600         gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
601         
602         priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
603                                                               G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
604
605 }
606         
607 static void
608 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
609 {
610         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
611
612         if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
613                                            priv->clipboard_change_handler_id))
614                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
615                                              priv->clipboard_change_handler_id);
616 }
617
618 static void
619 modest_msg_edit_window_finalize (GObject *obj)
620 {
621         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
622
623         /* Sanity check: shouldn't be needed, the window mgr should
624            call this function before */
625         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
626         
627         if (priv->draft_msg != NULL) {
628                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
629                 if (TNY_IS_HEADER (header)) {
630                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
631                         modest_window_mgr_unregister_header (mgr, header);
632                 }
633                 g_object_unref (priv->draft_msg);
634                 priv->draft_msg = NULL;
635         }
636         if (priv->outbox_msg != NULL) {
637                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
638                 if (TNY_IS_HEADER (header)) {
639                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
640                         modest_window_mgr_unregister_header (mgr, header);
641                 }
642                 g_object_unref (priv->outbox_msg);
643                 priv->outbox_msg = NULL;
644         }
645         if (priv->msg_uid != NULL) {
646                 g_free (priv->msg_uid);
647                 priv->msg_uid = NULL;
648         }
649
650         /* This had to stay alive for as long as the combobox that used it: */
651         modest_pair_list_free (priv->from_field_protos);
652         
653         G_OBJECT_CLASS(parent_class)->finalize (obj);
654 }
655
656 static GtkWidget *
657 menubar_to_menu (GtkUIManager *ui_manager)
658 {
659         GtkWidget *main_menu;
660         GtkWidget *menubar;
661         GList *iter;
662
663         /* Create new main menu */
664         main_menu = gtk_menu_new();
665
666         /* Get the menubar from the UI manager */
667         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
668
669         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
670         while (iter) {
671                 GtkWidget *menu;
672
673                 menu = GTK_WIDGET (iter->data);
674                 gtk_widget_reparent(menu, main_menu);
675
676                 iter = g_list_next (iter);
677         }
678         return main_menu;
679 }
680
681 static GdkPixbuf *
682 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type)
683 {
684         GdkPixbufLoader *loader;
685         GdkPixbuf *pixbuf;
686
687         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
688
689         if (loader == NULL)
690                 return NULL;
691
692         tny_stream_reset (TNY_STREAM (stream));
693         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
694                 unsigned char read_buffer[128];
695                 gint readed;
696                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
697                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
698                         break;
699         }
700
701         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
702         g_object_ref (pixbuf);
703         gdk_pixbuf_loader_close (loader, NULL);
704         g_object_unref (loader);
705
706         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
707                 GdkPixbuf *new_pixbuf;
708                 gint new_height;
709                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
710                         gdk_pixbuf_get_width (pixbuf);
711                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
712                 g_object_unref (pixbuf);
713                 pixbuf = new_pixbuf;
714         }
715
716         return pixbuf;
717 }
718
719 static void
720 replace_with_attachments (ModestMsgEditWindow *self, GList *attachments)
721 {
722         ModestMsgEditWindowPrivate *priv;
723         GList *node;
724
725         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
726
727         for (node = attachments; node != NULL; node = g_list_next (node)) {
728                 TnyMimePart *part = (TnyMimePart *) node->data;
729                 const gchar *cid = tny_mime_part_get_content_id (part);
730                 const gchar *mime_type = tny_mime_part_get_content_type (part);
731                 if ((cid != NULL)&&(mime_type != NULL)) {
732                         TnyStream *stream = tny_mime_part_get_stream (part);
733                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type);
734                         g_object_unref (stream);
735
736                         if (pixbuf != NULL) {
737 /*                              wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf); */
738                                 g_object_unref (pixbuf);
739                         }
740                 }
741         }
742 }
743
744 static void
745 update_last_cid (ModestMsgEditWindow *self, GList *attachments)
746 {
747         GList *node;
748         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
749
750         for (node = attachments; node != NULL; node = g_list_next (node)) {
751                 TnyMimePart *part = (TnyMimePart *) node->data;
752                 const gchar *cid = tny_mime_part_get_content_id (part);
753                 if (cid != NULL) {
754                         char *invalid = NULL;
755                         gint int_cid = strtol (cid, &invalid, 10);
756                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid > priv->last_cid)) {
757                                 priv->last_cid = int_cid;
758                         }
759                 }
760                 
761         }
762 }
763
764 static void
765 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
766 {
767         TnyHeader *header;
768         const gchar *to, *cc, *bcc, *subject;
769         gchar *body;
770         ModestMsgEditWindowPrivate *priv;
771         GtkTextIter iter;
772         TnyHeaderFlags priority_flags;
773         TnyFolder *msg_folder;
774         gboolean is_html = FALSE;
775         
776         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
777         g_return_if_fail (TNY_IS_MSG (msg));
778
779         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
780
781         header = tny_msg_get_header (msg);
782         to      = tny_header_get_to (header);
783         cc      = tny_header_get_cc (header);
784         bcc     = tny_header_get_bcc (header);
785         subject = tny_header_get_subject (header);
786         priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
787
788         if (to)
789                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
790         if (cc) {
791                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
792                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
793                 gtk_widget_show (priv->cc_caption);
794         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
795                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
796                 gtk_widget_hide (priv->cc_caption);
797         }
798         if (bcc) {
799                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
800                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
801                 gtk_widget_show (priv->bcc_caption);
802         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
803                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
804                 gtk_widget_hide (priv->bcc_caption);
805         } 
806         if (subject)
807                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
808         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
809                                                    priority_flags);
810
811         update_window_title (self);
812
813         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
814         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
815
816         if ((body == NULL)||(body[0] == '\0')) {
817                 g_free (body);
818                 body = modest_text_utils_convert_to_html ("");
819                 is_html = FALSE;
820         }
821         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
822         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
823                                             (gchar *) body,
824                                             strlen (body));
825         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
826         g_free (body);
827
828         if (preserve_is_rich && !is_html) {
829                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
830         /* Get the default format required from configuration */
831         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
832                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
833         }
834
835         /* Set the default focus depending on having already a To: field or not */
836         if ((!to)||(*to == '\0')) {
837                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
838         } else {
839                 gtk_widget_grab_focus (priv->msg_body);
840         }
841
842         /* TODO: lower priority, select in the From: combo to the
843            value that comes from msg <- not sure, should it be
844            allowed? */
845         
846         /* Add attachments to the view */
847         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
848         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
849         if (priv->attachments == NULL) {
850                 gtk_widget_hide (priv->attachments_caption);
851         } else {
852                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
853                 gtk_widget_show_all (priv->attachments_caption);
854                 replace_with_attachments (self, priv->attachments);
855         }
856         update_last_cid (self, priv->attachments);
857
858         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
859
860         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
861         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
862
863         reset_modified (self);
864
865         update_dimmed (self);
866         text_buffer_can_undo (priv->text_buffer, FALSE, self);
867         text_buffer_can_redo (priv->text_buffer, FALSE, self);
868
869         if (priv->msg_uid) {
870                 g_free (priv->msg_uid);
871                 priv->msg_uid = NULL;
872         }
873
874         /* we should set a reference to the incoming message if it is a draft */
875         msg_folder = tny_msg_get_folder (msg);
876         if (msg_folder) {               
877                 if (modest_tny_folder_is_local_folder (msg_folder)) {
878                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
879                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
880                                 priv->draft_msg = g_object_ref(msg);
881                         if (type == TNY_FOLDER_TYPE_OUTBOX)
882                                 priv->outbox_msg = g_object_ref(msg);
883                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
884                 }
885                 g_object_unref (msg_folder);
886         }
887 }
888
889 static void
890 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
891                                 gpointer data)
892 {
893         GList *item_children, *node;
894         GtkWidget *bin_child;
895
896         bin_child = gtk_bin_get_child (GTK_BIN(item));
897
898         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
899         
900         for (node = item_children; node != NULL; node = g_list_next (node)) {
901                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
902                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
903                 }
904         }
905         g_list_free (item_children);
906 }
907
908 static void
909 menu_tool_button_dont_expand (GtkMenuToolButton *item)
910 {
911         GtkWidget *box;
912         GList *item_children, *node;
913
914         box = gtk_bin_get_child (GTK_BIN (item));
915         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
916         item_children = gtk_container_get_children (GTK_CONTAINER (box));
917         
918         for (node = item_children; node != NULL; node = g_list_next (node)) {
919                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
920                 if (GTK_IS_TOGGLE_BUTTON (node->data))
921                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
922                 else if (GTK_IS_BUTTON (node->data))
923                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
924         }
925         g_list_free (item_children);
926 }
927
928
929 static void
930 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
931 {
932         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
933         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
934         GtkWidget *placeholder;
935         GtkWidget *tool_item;
936         gint insert_index;
937         gchar size_text[5];
938         gint size_index;
939         gint font_index;
940         GtkWidget *sizes_menu;
941         GtkWidget *fonts_menu;
942         GSList *radio_group = NULL;
943         GSList *node = NULL;
944         gchar *markup;
945
946         /* Toolbar */
947         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
948         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
949
950         /* should we hide the toolbar? */
951         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
952                 gtk_widget_hide (parent_priv->toolbar);
953
954         /* Font color placeholder */
955         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
956         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
957
958         /* font color */
959         tool_item = GTK_WIDGET (gtk_tool_item_new ());
960         priv->font_color_button = hildon_color_button_new ();
961         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
962         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
963         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
964         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
965         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
966         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
967         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
968
969         /* Font size and face placeholder */
970         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
971         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
972         /* font_size */
973         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
974         priv->size_tool_button_label = gtk_label_new (NULL);
975         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
976         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
977                               size_text,"</span>", NULL);
978         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
979         g_free (markup);
980         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
981         sizes_menu = gtk_menu_new ();
982         priv->size_items_group = NULL;
983         radio_group = NULL;
984         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
985                 GtkWidget *size_menu_item;
986
987                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
988                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
989                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
990                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
991                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
992                 gtk_widget_show (size_menu_item);
993
994                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
995                         
996         }
997
998         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
999                 GtkWidget *item = (GtkWidget *) node->data;
1000                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1001                                   window);
1002         }
1003
1004         priv->size_items_group = g_slist_reverse (priv->size_items_group);
1005         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1006         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1007         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1008         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1009         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1010         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1011         priv->font_size_toolitem = tool_item;
1012
1013         /* font face */
1014         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1015         priv->font_tool_button_label = gtk_label_new (NULL);
1016         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1017         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1018         g_free(markup);
1019         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1020         fonts_menu = gtk_menu_new ();
1021         priv->font_items_group = NULL;
1022         radio_group = NULL;
1023         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1024                 GtkWidget *font_menu_item;
1025                 GtkWidget *child_label;
1026
1027                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1028                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1029                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
1030                                       wp_get_font_name (font_index), "</span>", NULL);
1031                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1032                 g_free (markup);
1033                 
1034                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1035                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1036                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1037                 gtk_widget_show (font_menu_item);
1038
1039                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1040                         
1041         }
1042         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1043                 GtkWidget *item = (GtkWidget *) node->data;
1044                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1045                                   window);
1046         }
1047         priv->font_items_group = g_slist_reverse (priv->font_items_group);
1048         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1049         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1050         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1051         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1052         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1053         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1054         priv->font_face_toolitem = tool_item;
1055
1056         /* Set expand and homogeneous for remaining items */
1057         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1058         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1059         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1060         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1061         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1062         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1063         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1064         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1065         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1066
1067
1068 }
1069
1070
1071
1072 ModestWindow*
1073 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1074 {
1075         GObject *obj;
1076         ModestWindowPrivate *parent_priv;
1077         ModestMsgEditWindowPrivate *priv;
1078         GtkActionGroup *action_group;
1079         GError *error = NULL;
1080         GdkPixbuf *window_icon = NULL;
1081         GtkAction *action;
1082         ModestConf *conf;
1083         gboolean prefer_formatted;
1084         gint file_format;
1085         ModestPair *account_pair = NULL;
1086
1087         g_return_val_if_fail (msg, NULL);
1088         g_return_val_if_fail (account_name, NULL);
1089         
1090         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1091
1092         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1093         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1094
1095         parent_priv->ui_manager = gtk_ui_manager_new();
1096         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1097         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1098
1099         /* Add common actions */
1100         gtk_action_group_add_actions (action_group,
1101                                       modest_msg_edit_action_entries,
1102                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
1103                                       obj);
1104         gtk_action_group_add_toggle_actions (action_group,
1105                                              modest_msg_edit_toggle_action_entries,
1106                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1107                                              obj);
1108         gtk_action_group_add_radio_actions (action_group,
1109                                             modest_msg_edit_alignment_radio_action_entries,
1110                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1111                                             GTK_JUSTIFY_LEFT,
1112                                             G_CALLBACK (modest_ui_actions_on_change_justify),
1113                                             obj);
1114         gtk_action_group_add_radio_actions (action_group,
1115                                             modest_msg_edit_zoom_action_entries,
1116                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1117                                             100,
1118                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
1119                                             obj);
1120         gtk_action_group_add_radio_actions (action_group,
1121                                             modest_msg_edit_priority_action_entries,
1122                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1123                                             0,
1124                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1125                                             obj);
1126         gtk_action_group_add_radio_actions (action_group,
1127                                             modest_msg_edit_file_format_action_entries,
1128                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1129                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1130                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1131                                             obj);
1132         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1133         g_object_unref (action_group);
1134
1135         /* Load the UI definition */
1136         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1137                                          &error);
1138         if (error != NULL) {
1139                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1140                 g_clear_error (&error);
1141         }
1142
1143         /* Add accelerators */
1144         gtk_window_add_accel_group (GTK_WINDOW (obj), 
1145                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1146
1147         /* Menubar */
1148         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1149         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1150
1151         /* Init window */
1152         init_window (MODEST_MSG_EDIT_WINDOW(obj));
1153
1154         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1155                 
1156         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1157
1158         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1159         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1160
1161         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1162
1163         account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1164         if (account_pair != NULL)
1165                 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1166
1167         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1168
1169         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1170
1171         /* Set window icon */
1172         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1173         if (window_icon) {
1174                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1175                 g_object_unref (window_icon);
1176         }
1177
1178         /* Dim at start clipboard actions */
1179         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1180         gtk_action_set_sensitive (action, FALSE);
1181         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1182         gtk_action_set_sensitive (action, FALSE);
1183         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1184         gtk_action_set_sensitive (action, FALSE);
1185
1186         /* Update select all */
1187         update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1188         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1189         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1190         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1191         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1192
1193         /* set initial state of cc and bcc */
1194         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1195         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1196                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1197         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1198         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1199                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1200
1201         /* Setup the file format */
1202         conf = modest_runtime_get_conf ();
1203         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1204         if (error) {
1205                 g_clear_error (&error);
1206                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1207         } else
1208                 file_format = (prefer_formatted) ? 
1209                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
1210                         MODEST_FILE_FORMAT_PLAIN_TEXT;
1211         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1212
1213         update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1214         priv->update_caption_visibility = TRUE;
1215
1216         reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1217         
1218         return (ModestWindow*) obj;
1219 }
1220
1221 static gint
1222 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1223 {
1224         GString **string_buffer = (GString **) user_data;
1225
1226         *string_buffer = g_string_append (*string_buffer, buffer);
1227    
1228         return 0;
1229 }
1230
1231 /**
1232  * @result: A new string which should be freed with g_free().
1233  */
1234 static gchar *
1235 get_formatted_data (ModestMsgEditWindow *edit_window)
1236 {
1237         ModestMsgEditWindowPrivate *priv;
1238         GString *string_buffer = g_string_new ("");
1239         
1240         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1241
1242         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1243
1244         return g_string_free (string_buffer, FALSE);
1245                                                                         
1246 }
1247
1248 MsgData * 
1249 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1250 {
1251         MsgData *data;
1252         const gchar *account_name;
1253         ModestMsgEditWindowPrivate *priv;
1254         
1255         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1256
1257         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1258                                                                         
1259         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1260         g_return_val_if_fail (account_name, NULL);
1261         
1262         
1263         /* don't free these (except from) */
1264         data = g_slice_new0 (MsgData);
1265         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1266                                                              account_name);
1267         data->account_name = g_strdup (account_name);
1268         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1269         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1270         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1271         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1272         if (priv->draft_msg) {
1273                 data->draft_msg = g_object_ref (priv->draft_msg);
1274         } else 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                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2742                 return FALSE;
2743         }
2744         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
2745                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2746                 return FALSE;
2747         }
2748         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2749                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2750                 return FALSE;
2751         }
2752
2753         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2754             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2755                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2756
2757         return TRUE;
2758
2759 }
2760
2761 static void
2762 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2763                                                ModestMsgEditWindow *window)
2764 {
2765         modest_msg_edit_window_offer_attach_file (window);
2766 }
2767
2768 static void
2769 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2770                                                GdkEvent *event,
2771                                                ModestMsgEditWindow *window)
2772 {
2773         ModestWindowPrivate *parent_priv;
2774         ModestMsgEditWindowPrivate *priv;
2775         GtkAction *action;
2776         GList *selected_attachments = NULL;
2777         gint n_att_selected = 0;
2778
2779         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2780         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2781
2782         if (!GTK_WIDGET_VISIBLE (window))
2783                 return;
2784
2785         selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2786         n_att_selected = g_list_length (selected_attachments);
2787         g_list_free (selected_attachments);
2788
2789         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2790         gtk_action_set_sensitive (action, n_att_selected == 1);
2791         
2792         update_copy_cut_dimming (window);
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_copy_cut_dimming (ModestMsgEditWindow *window)
3027 {
3028         ModestWindowPrivate *parent_priv = NULL;
3029         ModestMsgEditWindowPrivate *priv = NULL;
3030         GtkClipboard *clipboard = NULL;
3031         GtkAction *action = NULL;
3032         gboolean has_selection = FALSE;
3033         GtkWidget *focused = NULL;
3034         gchar *selection = NULL;
3035         guint i, j;
3036
3037         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3038         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3039         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3040         focused = gtk_window_get_focus (GTK_WINDOW (window));
3041
3042
3043         if (GTK_IS_EDITABLE (focused)) {
3044                 gtk_editable_get_selection_bounds (GTK_EDITABLE (focused), 
3045                                                    &i, &j);
3046                 
3047                 has_selection = i!= 0 && j != 0;
3048         }
3049
3050 /*      has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL); */
3051 /*      has_selection = selection != NULL; */
3052
3053         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3054         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3055         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3056         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3057
3058         if (selection != NULL) 
3059                 g_free(selection);
3060 }
3061
3062 static void 
3063 update_paste_dimming (ModestMsgEditWindow *window)
3064 {
3065         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3066         GtkAction *action = NULL;
3067         GtkClipboard *clipboard = NULL;
3068         ModestEmailClipboard *e_clipboard;
3069         GtkWidget *focused;
3070         gboolean active;
3071
3072         focused = gtk_window_get_focus (GTK_WINDOW (window));
3073
3074         e_clipboard = modest_runtime_get_email_clipboard ();
3075         if (!modest_email_clipboard_cleared (e_clipboard)) {
3076                 active = TRUE;
3077         } else {
3078                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3079                 active = gtk_clipboard_wait_is_text_available (clipboard);
3080         }
3081
3082         if (active) {
3083                 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3084                         active = FALSE;
3085         }
3086
3087         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3088         gtk_action_set_sensitive (action, active);
3089
3090 }
3091
3092 static void 
3093 update_select_all_dimming (ModestMsgEditWindow *window)
3094 {
3095         GtkWidget *focused;
3096         gboolean dimmed = FALSE;
3097         GtkAction *action;
3098         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3099
3100         focused = gtk_window_get_focus (GTK_WINDOW (window));
3101         if (GTK_IS_ENTRY (focused)) {
3102                 const gchar *current_text;
3103                 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3104                 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3105         } else if (GTK_IS_TEXT_VIEW (focused)) {
3106                 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3107                 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3108         } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3109                 dimmed = FALSE;
3110         }
3111         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3112         gtk_action_set_sensitive (action, !dimmed);
3113 }
3114
3115 static void 
3116 update_zoom_dimming (ModestMsgEditWindow *window)
3117 {
3118         GtkWidget *focused;
3119         gboolean dimmed = FALSE;
3120         GtkAction *action;
3121         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3122
3123         focused = gtk_window_get_focus (GTK_WINDOW (window));
3124         dimmed = ! WP_IS_TEXT_VIEW (focused);
3125         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3126         gtk_action_set_sensitive (action, !dimmed);
3127 }
3128
3129 static void
3130 edit_menu_activated (GtkAction *action,
3131                      gpointer userdata)
3132 {
3133         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3134
3135         update_select_all_dimming (window);
3136         update_copy_cut_dimming (window);
3137         update_paste_dimming (window);
3138 }
3139 static void
3140 view_menu_activated (GtkAction *action,
3141                      gpointer userdata)
3142 {
3143         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3144
3145         update_zoom_dimming (window);
3146 }
3147
3148 gboolean 
3149 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3150 {
3151         ModestMsgEditWindowPrivate *priv;
3152
3153         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3154         return priv->sent;
3155 }
3156
3157 void 
3158 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3159                                  gboolean sent)
3160 {
3161         ModestMsgEditWindowPrivate *priv;
3162
3163         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3164         priv->sent = sent;
3165 }
3166
3167
3168 void            
3169 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3170                                   TnyMsg *draft)
3171 {
3172         ModestMsgEditWindowPrivate *priv;
3173         TnyHeader *header = NULL;
3174
3175         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3176         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3177
3178         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3179         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3180
3181         if (priv->draft_msg != NULL) {
3182                 header = tny_msg_get_header (priv->draft_msg);
3183                 if (TNY_IS_HEADER (header)) {
3184                         modest_window_mgr_unregister_header (mgr, header);
3185                 }
3186                 g_object_unref (priv->draft_msg);
3187         }
3188
3189         if (draft != NULL) {
3190                 g_object_ref (draft);
3191                 header = tny_msg_get_header (draft);
3192                 if (TNY_IS_HEADER (header))
3193                         modest_window_mgr_register_header (mgr, header);
3194                 if (priv->msg_uid) {
3195                         g_free (priv->msg_uid);
3196                         priv->msg_uid = NULL;
3197                 }
3198                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3199         }
3200
3201         priv->draft_msg = draft;