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