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