4f0e79f5ec2b0ffa8c99e4d92ff41d4f891c58c5
[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         /* should we hide the toolbar? */
970         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
971                 gtk_widget_hide (parent_priv->toolbar);
972
973         /* Font color placeholder */
974         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
975         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
976
977         /* font color */
978         tool_item = GTK_WIDGET (gtk_tool_item_new ());
979         priv->font_color_button = hildon_color_button_new ();
980         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
981         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
982         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
983         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
984         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
985         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
986         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
987
988         /* Font size and face placeholder */
989         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
990         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
991         /* font_size */
992         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
993         priv->size_tool_button_label = gtk_label_new (NULL);
994         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
995         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
996                               size_text,"</span>", NULL);
997         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
998         g_free (markup);
999         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1000         sizes_menu = gtk_menu_new ();
1001         priv->size_items_group = NULL;
1002         radio_group = NULL;
1003         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1004                 GtkWidget *size_menu_item;
1005
1006                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1007                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1008                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1009                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1010                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1011                 gtk_widget_show (size_menu_item);
1012
1013                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1014                         
1015         }
1016
1017         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1018                 GtkWidget *item = (GtkWidget *) node->data;
1019                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1020                                   window);
1021         }
1022
1023         priv->size_items_group = g_slist_reverse (priv->size_items_group);
1024         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1025         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1026         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1027         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1028         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1029         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1030         priv->font_size_toolitem = tool_item;
1031
1032         /* font face */
1033         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1034         priv->font_tool_button_label = gtk_label_new (NULL);
1035         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1036         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1037         g_free(markup);
1038         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1039         fonts_menu = gtk_menu_new ();
1040         priv->font_items_group = NULL;
1041         radio_group = NULL;
1042         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1043                 GtkWidget *font_menu_item;
1044                 GtkWidget *child_label;
1045
1046                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1047                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1048                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
1049                                       wp_get_font_name (font_index), "</span>", NULL);
1050                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1051                 g_free (markup);
1052                 
1053                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1054                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1055                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1056                 gtk_widget_show (font_menu_item);
1057
1058                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1059                         
1060         }
1061         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1062                 GtkWidget *item = (GtkWidget *) node->data;
1063                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1064                                   window);
1065         }
1066         priv->font_items_group = g_slist_reverse (priv->font_items_group);
1067         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1068         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1069         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1070         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1071         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1072         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1073         priv->font_face_toolitem = tool_item;
1074
1075         /* Set expand and homogeneous for remaining items */
1076         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1077         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1078         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1079         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1080         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1081         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1082         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1083         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1084         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1085
1086
1087 }
1088
1089
1090
1091 ModestWindow*
1092 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1093 {
1094         GObject *obj;
1095         ModestWindowPrivate *parent_priv;
1096         ModestMsgEditWindowPrivate *priv;
1097         GtkActionGroup *action_group;
1098         GError *error = NULL;
1099         GdkPixbuf *window_icon = NULL;
1100         GtkAction *action;
1101         ModestConf *conf;
1102         gboolean prefer_formatted;
1103         gint file_format;
1104         ModestPair *account_pair = NULL;
1105
1106         g_return_val_if_fail (msg, NULL);
1107         g_return_val_if_fail (account_name, NULL);
1108         
1109         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
1110
1111         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1112         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1113
1114         parent_priv->ui_manager = gtk_ui_manager_new();
1115         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
1116         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1117
1118         /* Add common actions */
1119         gtk_action_group_add_actions (action_group,
1120                                       modest_msg_edit_action_entries,
1121                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
1122                                       obj);
1123         gtk_action_group_add_toggle_actions (action_group,
1124                                              modest_msg_edit_toggle_action_entries,
1125                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
1126                                              obj);
1127         gtk_action_group_add_radio_actions (action_group,
1128                                             modest_msg_edit_alignment_radio_action_entries,
1129                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
1130                                             GTK_JUSTIFY_LEFT,
1131                                             G_CALLBACK (modest_ui_actions_on_change_justify),
1132                                             obj);
1133         gtk_action_group_add_radio_actions (action_group,
1134                                             modest_msg_edit_zoom_action_entries,
1135                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
1136                                             100,
1137                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
1138                                             obj);
1139         gtk_action_group_add_radio_actions (action_group,
1140                                             modest_msg_edit_priority_action_entries,
1141                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
1142                                             0,
1143                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
1144                                             obj);
1145         gtk_action_group_add_radio_actions (action_group,
1146                                             modest_msg_edit_file_format_action_entries,
1147                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
1148                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
1149                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
1150                                             obj);
1151         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1152         g_object_unref (action_group);
1153
1154         /* Load the UI definition */
1155         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
1156                                          &error);
1157         if (error != NULL) {
1158                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
1159                 g_clear_error (&error);
1160         }
1161
1162         /* Add accelerators */
1163         gtk_window_add_accel_group (GTK_WINDOW (obj), 
1164                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1165
1166         /* Menubar */
1167         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
1168         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
1169
1170         /* Init window */
1171         init_window (MODEST_MSG_EDIT_WINDOW(obj));
1172
1173         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1174                 
1175         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1176
1177         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1178         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1179
1180         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
1181
1182         account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
1183         if (account_pair != NULL)
1184                 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
1185
1186         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1187
1188         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1189
1190         /* Set window icon */
1191         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
1192         if (window_icon) {
1193                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
1194                 g_object_unref (window_icon);
1195         }
1196
1197         /* Dim at start clipboard actions */
1198         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
1199         gtk_action_set_sensitive (action, FALSE);
1200         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
1201         gtk_action_set_sensitive (action, FALSE);
1202         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
1203         gtk_action_set_sensitive (action, FALSE);
1204
1205         /* Update select all */
1206         update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1207         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
1208         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
1209         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
1210         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
1211
1212         /* set initial state of cc and bcc */
1213         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
1214         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1215                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
1216         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
1217         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1218                                                modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
1219
1220         /* Setup the file format */
1221         conf = modest_runtime_get_conf ();
1222         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
1223         if (error) {
1224                 g_clear_error (&error);
1225                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
1226         } else
1227                 file_format = (prefer_formatted) ? 
1228                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
1229                         MODEST_FILE_FORMAT_PLAIN_TEXT;
1230         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
1231
1232         update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
1233         priv->update_caption_visibility = TRUE;
1234
1235         reset_modified (MODEST_MSG_EDIT_WINDOW (obj));
1236         
1237         return (ModestWindow*) obj;
1238 }
1239
1240 static gint
1241 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1242 {
1243         GString **string_buffer = (GString **) user_data;
1244
1245         *string_buffer = g_string_append (*string_buffer, buffer);
1246    
1247         return 0;
1248 }
1249
1250 /**
1251  * @result: A new string which should be freed with g_free().
1252  */
1253 static gchar *
1254 get_formatted_data (ModestMsgEditWindow *edit_window)
1255 {
1256         ModestMsgEditWindowPrivate *priv;
1257         GString *string_buffer = g_string_new ("");
1258         
1259         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1260
1261         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1262
1263         return g_string_free (string_buffer, FALSE);
1264                                                                         
1265 }
1266
1267 MsgData * 
1268 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1269 {
1270         MsgData *data;
1271         const gchar *account_name;
1272         ModestMsgEditWindowPrivate *priv;
1273         
1274         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1275
1276         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1277                                                                         
1278         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1279         g_return_val_if_fail (account_name, NULL);
1280         
1281         
1282         /* don't free these (except from) */
1283         data = g_slice_new0 (MsgData);
1284         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1285                                                              account_name);
1286         data->account_name = g_strdup (account_name);
1287         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1288         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1289         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1290         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1291         if (priv->draft_msg) {
1292                 data->draft_msg = g_object_ref (priv->draft_msg);
1293         } else if (priv->outbox_msg) {
1294                 data->draft_msg = g_object_ref (priv->outbox_msg);
1295         } else {
1296                 data->draft_msg = NULL;
1297         }
1298
1299         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1300         GtkTextIter b, e;
1301         gtk_text_buffer_get_bounds (buf, &b, &e);
1302         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1303
1304         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1305                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1306         else
1307                 data->html_body = NULL;
1308
1309         /* deep-copy the data */
1310         GList *cursor = priv->attachments;
1311         data->attachments = NULL;
1312         while (cursor) {
1313                 if (!(TNY_IS_MIME_PART(cursor->data))) {
1314                         g_warning ("strange data in attachment list");
1315                         cursor = g_list_next (cursor);
1316                         continue;
1317                 }
1318                 data->attachments = g_list_append (data->attachments,
1319                                                    g_object_ref (cursor->data));
1320                 cursor = g_list_next (cursor);
1321         }
1322         
1323         data->priority_flags = priv->priority_flags;
1324
1325         return data;
1326 }
1327
1328
1329 static void
1330 unref_gobject (GObject *obj, gpointer data)
1331 {
1332         if (!G_IS_OBJECT(obj))
1333                 return;
1334         g_object_unref (obj);
1335 }
1336
1337 void 
1338 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1339                                                       MsgData *data)
1340 {
1341         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1342
1343         if (!data)
1344                 return;
1345
1346         g_free (data->to);
1347         g_free (data->cc);
1348         g_free (data->bcc);
1349         g_free (data->subject);
1350         g_free (data->plain_body);
1351         g_free (data->html_body);
1352         g_free (data->account_name);
1353         
1354         if (data->draft_msg != NULL) {
1355                 g_object_unref (data->draft_msg);
1356                 data->draft_msg = NULL;
1357         }
1358         
1359         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1360         g_list_free (data->attachments);
1361         
1362         g_slice_free (MsgData, data);
1363 }
1364
1365 ModestMsgEditFormat
1366 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1367 {
1368         gboolean rich_text;
1369         ModestMsgEditWindowPrivate *priv = NULL;
1370         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1371
1372         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1373
1374         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1375         if (rich_text)
1376                 return MODEST_MSG_EDIT_FORMAT_HTML;
1377         else
1378                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1379 }
1380
1381 void
1382 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1383                                    ModestMsgEditFormat format)
1384 {
1385         ModestMsgEditWindowPrivate *priv;
1386
1387         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1388         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1389
1390         switch (format) {
1391         case MODEST_MSG_EDIT_FORMAT_HTML:
1392                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1393                 break;
1394         case MODEST_MSG_EDIT_FORMAT_TEXT:
1395                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1396                 break;
1397         default:
1398                 g_return_if_reached ();
1399         }
1400 }
1401
1402 ModestMsgEditFormatState *
1403 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1404 {
1405         ModestMsgEditFormatState *format_state = NULL;
1406         ModestMsgEditWindowPrivate *priv;
1407         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1408
1409         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1410         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1411
1412         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1413
1414         format_state = g_new0 (ModestMsgEditFormatState, 1);
1415         format_state->bold = buffer_format->bold&0x1;
1416         format_state->italics = buffer_format->italic&0x1;
1417         format_state->bullet = buffer_format->bullet&0x1;
1418         format_state->color = buffer_format->color;
1419         format_state->font_size = buffer_format->font_size;
1420         format_state->font_family = wp_get_font_name (buffer_format->font);
1421         format_state->justification = buffer_format->justification;
1422         g_free (buffer_format);
1423
1424         return format_state;
1425  
1426 }
1427
1428 void
1429 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1430                                          const ModestMsgEditFormatState *format_state)
1431 {
1432         ModestMsgEditWindowPrivate *priv;
1433         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1434         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1435         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1436         g_return_if_fail (format_state != NULL);
1437
1438         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1439         gtk_widget_grab_focus (priv->msg_body);
1440         buffer_format->bold = (format_state->bold != FALSE);
1441         buffer_format->italic = (format_state->italics != FALSE);
1442         buffer_format->color = format_state->color;
1443         buffer_format->font_size = format_state->font_size;
1444         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1445         buffer_format->justification = format_state->justification;
1446         buffer_format->bullet = format_state->bullet;
1447
1448         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1449
1450         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1451         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1452         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1453         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1454         buffer_format->cs.font = (buffer_format->font != current_format->font);
1455         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1456         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1457
1458         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1459         if (buffer_format->cs.bold) {
1460                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1461         }
1462         if (buffer_format->cs.italic) {
1463                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1464         }
1465         if (buffer_format->cs.color) {
1466                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1467         }
1468         if (buffer_format->cs.font_size) {
1469                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1470         }
1471         if (buffer_format->cs.justification) {
1472                 switch (buffer_format->justification) {
1473                 case GTK_JUSTIFY_LEFT:
1474                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1475                         break;
1476                 case GTK_JUSTIFY_CENTER:
1477                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1478                         break;
1479                 case GTK_JUSTIFY_RIGHT:
1480                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1481                         break;
1482                 default:
1483                         break;
1484                 }
1485                         
1486         }
1487         if (buffer_format->cs.font) {
1488                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1489         }
1490         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1491         if (buffer_format->cs.bullet) {
1492           wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1493         }
1494 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1495
1496         g_free (current_format);
1497
1498 }
1499
1500 static void
1501 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1502 {
1503         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1504         GtkAction *action;
1505         ModestWindowPrivate *parent_priv;
1506         ModestMsgEditWindowPrivate *priv;
1507         GtkWidget *new_size_menuitem;
1508         GtkWidget *new_font_menuitem;
1509         
1510         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1511         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1512
1513         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1514                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1515                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1516                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1517         } else {
1518                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1519                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1520                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1521         }
1522
1523         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1524         
1525         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1526         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1527
1528         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1529         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1530
1531 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1532 /*      modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1533
1534         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1535                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1536                                          window);
1537         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1538         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1539                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1540                                            window);
1541
1542         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1543                                                       buffer_format->font_size))->data);
1544         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1545                 GtkWidget *label;
1546                 gchar *markup;
1547
1548                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1549                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1550                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1551                 g_free (markup);
1552                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1553                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1554                                                  window);
1555                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1556                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1557                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1558                                                    window);
1559         }
1560
1561         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1562                                                       buffer_format->font))->data);
1563         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1564                 GtkWidget *label;
1565                 gchar *markup;
1566
1567                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1568                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1569                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1570                 g_free (markup);
1571                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1572                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1573                                                  window);
1574                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1575                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1576                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1577                                                    window);
1578         }
1579
1580         g_free (buffer_format);
1581
1582 }
1583
1584
1585 void
1586 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1587 {
1588         
1589         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1590         ModestMsgEditWindowPrivate *priv;
1591         GtkWidget *dialog = NULL;
1592         gint response;
1593         const GdkColor *new_color = NULL;
1594         
1595         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1596         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1597         
1598 #ifdef MODEST_HILDON_VERSION_0  
1599         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1600         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1601 #else
1602         dialog = hildon_color_chooser_new ();
1603         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1604 #endif /*MODEST_HILDON_VERSION_0*/              
1605         g_free (buffer_format);
1606
1607         response = gtk_dialog_run (GTK_DIALOG (dialog));
1608         switch (response) {
1609         case GTK_RESPONSE_OK: {
1610 #ifdef MODEST_HILDON_VERSION_0
1611                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1612 #else
1613                 GdkColor col;
1614                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1615                 new_color = &col;
1616 #endif /*MODEST_HILDON_VERSION_0*/
1617         }
1618
1619         break;
1620         default:
1621                 break;
1622         }
1623         gtk_widget_destroy (dialog);
1624
1625         if (new_color != NULL)
1626                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1627
1628 }
1629
1630 void
1631 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1632 {
1633         
1634         ModestMsgEditWindowPrivate *priv;
1635         GtkWidget *dialog = NULL;
1636         gint response;
1637         GdkColor *old_color = NULL;
1638         const GdkColor *new_color = NULL;
1639         
1640         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1641         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1642         
1643 #ifdef MODEST_HILDON_VERSION_0  
1644         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1645         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1646 #else
1647         dialog = hildon_color_chooser_new ();
1648         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1649 #endif /*MODEST_HILDON_VERSION_9*/              
1650
1651         response = gtk_dialog_run (GTK_DIALOG (dialog));
1652         switch (response) {
1653         case GTK_RESPONSE_OK: {
1654 #ifdef MODEST_HILDON_VERSION_0
1655                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1656 #else
1657                 GdkColor col;
1658                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1659                 new_color = &col;
1660 #endif /*MODEST_HILDON_VERSION_0*/
1661           }
1662                 break;
1663         default:
1664                 break;
1665         }
1666         gtk_widget_destroy (dialog);
1667
1668         if (new_color != NULL)
1669                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1670
1671 }
1672
1673 static TnyStream* create_stream_for_uri (const gchar* uri)
1674 {
1675         if (!uri)
1676                 return NULL;
1677                 
1678         TnyStream *result = NULL;
1679
1680         GnomeVFSHandle *handle = NULL;
1681         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1682         if (test == GNOME_VFS_OK) {
1683                 /* Create the tinymail stream: */
1684                 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1685                 result = TNY_STREAM (tny_vfs_stream_new (handle));
1686         }
1687         
1688         return result;
1689 }
1690
1691 void
1692 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1693 {
1694         
1695         ModestMsgEditWindowPrivate *priv;
1696         GtkWidget *dialog = NULL;
1697         gint response = 0;
1698         GSList *uris = NULL;
1699         GSList *uri_node = NULL;
1700         
1701         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1702         
1703         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1704         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1705         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1706
1707         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1708
1709         response = gtk_dialog_run (GTK_DIALOG (dialog));
1710         switch (response) {
1711         case GTK_RESPONSE_OK:
1712                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1713                 break;
1714         default:
1715                 break;
1716         }
1717         gtk_widget_destroy (dialog);
1718
1719         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1720                 const gchar *uri;
1721                 GnomeVFSHandle *handle = NULL;
1722                 GnomeVFSResult result;
1723                 GtkTextIter position;
1724                 GtkTextMark *insert_mark;
1725
1726                 uri = (const gchar *) uri_node->data;
1727                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1728                 if (result == GNOME_VFS_OK) {
1729                         GdkPixbuf *pixbuf;
1730                         GnomeVFSFileInfo info;
1731                         gchar *filename, *basename, *escaped_filename;
1732                         TnyMimePart *mime_part;
1733                         gchar *content_id;
1734                         const gchar *mime_type = NULL;
1735                         GnomeVFSURI *vfs_uri;
1736
1737                         vfs_uri = gnome_vfs_uri_new (uri);
1738
1739                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1740                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1741                         g_free (escaped_filename);
1742                         gnome_vfs_uri_unref (vfs_uri);
1743
1744                         if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1745                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
1746                             == GNOME_VFS_OK)
1747                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1748
1749                         mime_part = tny_platform_factory_new_mime_part
1750                                 (modest_runtime_get_platform_factory ());
1751                                 
1752                         TnyStream *stream = create_stream_for_uri (uri);
1753                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1754                         
1755                         content_id = g_strdup_printf ("%d", priv->last_cid);
1756                         tny_mime_part_set_content_id (mime_part, content_id);
1757                         g_free (content_id);
1758                         priv->last_cid++;
1759                         
1760                         basename = g_path_get_basename (filename);
1761                         tny_mime_part_set_filename (mime_part, basename);
1762                         g_free (basename);
1763
1764                         pixbuf = pixbuf_from_stream (stream, mime_type);
1765                         
1766                         if (pixbuf != NULL) {
1767                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1768                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1769                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1770                         } 
1771
1772                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1773                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1774                                                                 mime_part);
1775                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1776                         gtk_widget_show_all (priv->attachments_caption);
1777                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1778                         g_free (filename);
1779
1780                 }
1781         }
1782
1783
1784 }
1785
1786 void
1787 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1788 {
1789         
1790         ModestMsgEditWindowPrivate *priv;
1791         GtkWidget *dialog = NULL;
1792         gint response = 0;
1793         GSList *uris = NULL;
1794         GSList *uri_node;
1795         
1796         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1797         
1798         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1799         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1800         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1801
1802         response = gtk_dialog_run (GTK_DIALOG (dialog));
1803         switch (response) {
1804         case GTK_RESPONSE_OK:
1805                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1806                 break;
1807         default:
1808                 break;
1809         }
1810         gtk_widget_destroy (dialog);
1811
1812         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1813                 const gchar *uri = (const gchar *) uri_node->data;
1814                 modest_msg_edit_window_attach_file_one (window, uri);
1815         }
1816         g_slist_foreach (uris, (GFunc) g_free, NULL);
1817         g_slist_free (uris);
1818 }
1819
1820 void
1821 modest_msg_edit_window_attach_file_one (
1822                 ModestMsgEditWindow *window,
1823                 const gchar *uri)
1824 {
1825         g_return_if_fail (window);
1826         g_return_if_fail (uri);
1827                 
1828         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1829         
1830         
1831         GnomeVFSHandle *handle = NULL;
1832         GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1833         if (result == GNOME_VFS_OK) {
1834                 TnyMimePart *mime_part;
1835                 TnyStream *stream;
1836                 const gchar *mime_type = NULL;
1837                 gchar *basename;
1838                 gchar *escaped_filename;
1839                 gchar *filename;
1840                 gchar *content_id;
1841                 GnomeVFSFileInfo info;
1842                 GnomeVFSURI *vfs_uri;
1843
1844                 vfs_uri = gnome_vfs_uri_new (uri);
1845                 
1846
1847                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1848                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1849                 g_free (escaped_filename);
1850                 gnome_vfs_uri_unref (vfs_uri);
1851                 
1852                 if (gnome_vfs_get_file_info (uri, 
1853                                              &info, 
1854                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
1855                                              GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
1856                     == GNOME_VFS_OK)
1857                         mime_type = gnome_vfs_file_info_get_mime_type (&info);
1858                 mime_part = tny_platform_factory_new_mime_part
1859                         (modest_runtime_get_platform_factory ());
1860                 stream = TNY_STREAM (tny_vfs_stream_new (handle));
1861                 
1862                 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1863                 
1864                 content_id = g_strdup_printf ("%d", priv->last_cid);
1865                 tny_mime_part_set_content_id (mime_part, content_id);
1866                 g_free (content_id);
1867                 priv->last_cid++;
1868                 
1869                 basename = g_path_get_basename (filename);
1870                 tny_mime_part_set_filename (mime_part, basename);
1871                 g_free (basename);
1872                 
1873                 priv->attachments = g_list_prepend (priv->attachments, mime_part);
1874                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1875                                                         mime_part);
1876                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1877                 gtk_widget_show_all (priv->attachments_caption);
1878                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1879                 g_free (filename);
1880         }
1881 }
1882
1883 void
1884 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1885                                           GList *att_list)
1886 {
1887         ModestMsgEditWindowPrivate *priv;
1888         gboolean clean_list = FALSE;
1889
1890         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1891         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1892
1893         if (att_list == NULL) {
1894                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1895                 clean_list = TRUE;
1896         }
1897
1898         if (att_list == NULL) {
1899                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1900         } else {
1901                 GtkWidget *confirmation_dialog = NULL;
1902                 gboolean dialog_response;
1903                 GList *node;
1904                 gchar *message = NULL;
1905                 const gchar *filename = NULL;
1906
1907                 if (att_list->next == NULL) {
1908                         filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1909                 } else {
1910                         filename = "";
1911                 }
1912                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1913                                                     att_list->next == NULL), filename);
1914                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1915                 g_free (message);
1916                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1917                 gtk_widget_destroy (confirmation_dialog);
1918                 if (!dialog_response) {
1919                         if (clean_list)
1920                                 g_list_free (att_list);
1921                         return;
1922                 }
1923                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1924
1925                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1926                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1927                         const gchar *att_id;
1928                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1929
1930                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1931                                                                    mime_part);
1932                         if (priv->attachments == NULL)
1933                                 gtk_widget_hide (priv->attachments_caption);
1934                         att_id = tny_mime_part_get_content_id (mime_part);
1935                         if (att_id != NULL)
1936                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1937                                                                  att_id);
1938                         g_object_unref (mime_part);
1939                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1940                 }
1941         }
1942
1943         if (clean_list)
1944                 g_list_free (att_list);
1945 }
1946
1947 static void
1948 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1949                                             gpointer userdata)
1950 {
1951         ModestMsgEditWindowPrivate *priv;
1952         GdkColor *new_color;
1953         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1954         
1955 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
1956         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1957 #else 
1958         GdkColor col;
1959         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1960         new_color = &col;
1961 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
1962
1963         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1964         
1965         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1966
1967 }
1968
1969 static void
1970 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1971                                     gpointer userdata)
1972 {
1973         ModestMsgEditWindowPrivate *priv;
1974         gint new_size_index;
1975         ModestMsgEditWindow *window;
1976         GtkWidget *label;
1977         
1978         window = MODEST_MSG_EDIT_WINDOW (userdata);
1979         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1980         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1981
1982         if (gtk_check_menu_item_get_active (menu_item)) {
1983                 gchar *markup;
1984                 WPTextBufferFormat format;
1985
1986                 memset (&format, 0, sizeof (format));
1987                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
1988
1989                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1990                 
1991                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1992                 format.cs.font_size = TRUE;
1993                 format.cs.text_position = TRUE;
1994                 format.cs.font = TRUE;
1995                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1996 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
1997
1998                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1999                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
2000                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2001                 
2002                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2003                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2004                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2005                 g_free (markup);
2006         }
2007 }
2008
2009 static void
2010 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2011                                     gpointer userdata)
2012 {
2013         ModestMsgEditWindowPrivate *priv;
2014         gint new_font_index;
2015         ModestMsgEditWindow *window;
2016         GtkWidget *label;
2017         
2018         window = MODEST_MSG_EDIT_WINDOW (userdata);
2019         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2020         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2021
2022         if (gtk_check_menu_item_get_active (menu_item)) {
2023                 gchar *markup;
2024
2025                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2026                 
2027                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2028
2029                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2030                                                    (gpointer) new_font_index))
2031                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2032                 
2033                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2034                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2035                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2036                 g_free (markup);
2037         }
2038 }
2039
2040 static void
2041 modest_msg_edit_window_set_zoom (ModestWindow *window,
2042                                  gdouble zoom)
2043 {
2044         ModestMsgEditWindowPrivate *priv;
2045         ModestWindowPrivate *parent_priv;
2046         GtkRadioAction *zoom_radio_action;
2047      
2048         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2049
2050         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2051         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2052         priv->zoom_level = zoom;
2053         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom*DEFAULT_FONT_SCALE);
2054
2055         /* Zoom level menu options should be updated with the current zoom level */
2056         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2057         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
2058                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2059 #ifdef MODEST_HAVE_HILDON0_WIDGETS
2060         /* FIXME: Not availible before Gtk 2.10 */
2061 #else
2062         gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
2063 #endif
2064 }
2065
2066 static gdouble
2067 modest_msg_edit_window_get_zoom (ModestWindow *window)
2068 {
2069         ModestMsgEditWindowPrivate *priv;
2070      
2071         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
2072
2073         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2074         return priv->zoom_level;
2075 }
2076
2077 static gboolean
2078 zoom_allowed (ModestMsgEditWindow *window)
2079 {
2080         GtkWidget *focus;
2081
2082         focus = gtk_window_get_focus (GTK_WINDOW (window));
2083         return (focus != NULL && WP_IS_TEXT_VIEW (focus));
2084 }
2085
2086 static gboolean
2087 modest_msg_edit_window_zoom_plus (ModestWindow *window)
2088 {
2089         ModestWindowPrivate *parent_priv;
2090         GtkRadioAction *zoom_radio_action;
2091         GSList *group, *node;
2092
2093         /* First we check if the text view is focused. If not, zooming is not allowed */
2094         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2095                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2096                 return FALSE;
2097         }
2098
2099         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2100         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
2101                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2102
2103         group = gtk_radio_action_get_group (zoom_radio_action);
2104
2105         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
2106                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
2107                 return FALSE;
2108         }
2109
2110         for (node = group; node != NULL; node = g_slist_next (node)) {
2111                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
2112                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
2113                         return TRUE;
2114                 }
2115         }
2116         return FALSE;
2117 }
2118
2119 static gboolean
2120 modest_msg_edit_window_zoom_minus (ModestWindow *window)
2121 {
2122         ModestWindowPrivate *parent_priv;
2123         GtkRadioAction *zoom_radio_action;
2124         GSList *group, *node;
2125
2126         /* First we check if the text view is focused. If not, zooming is not allowed */
2127         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
2128                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2129                 return FALSE;
2130         }
2131
2132         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2133         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
2134                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
2135
2136         group = gtk_radio_action_get_group (zoom_radio_action);
2137
2138         for (node = group; node != NULL; node = g_slist_next (node)) {
2139                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
2140                         if (node->next != NULL) {
2141                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
2142                                 return TRUE;
2143                         } else
2144                                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
2145                         break;
2146                 }
2147         }
2148         return FALSE;
2149 }
2150
2151 static gboolean
2152 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2153 {
2154         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2155                 ModestWindowPrivate *parent_priv;
2156                 ModestWindowMgr *mgr;
2157                 gboolean is_fullscreen;
2158                 GtkAction *fs_toggle_action;
2159                 gboolean active;
2160
2161                 mgr = modest_runtime_get_window_mgr ();
2162                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2163
2164                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2165                 
2166                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2167                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2168                 if (is_fullscreen != active)
2169                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2170         }
2171
2172         return FALSE;
2173
2174 }
2175
2176 void
2177 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
2178 {
2179         ModestWindowPrivate *parent_priv;
2180         GtkAction *fs_toggle_action;
2181         gboolean active;
2182
2183         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2184
2185         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2186         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
2187         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
2188 }
2189
2190 void
2191 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2192                                 gboolean show)
2193 {
2194         ModestMsgEditWindowPrivate *priv = NULL;
2195         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2196
2197         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2198         if (!priv->update_caption_visibility)
2199                 return;
2200
2201         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2202         if (show)
2203                 gtk_widget_show (priv->cc_caption);
2204         else
2205                 gtk_widget_hide (priv->cc_caption);
2206
2207         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2208 }
2209
2210 void
2211 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2212                                  gboolean show)
2213 {
2214         ModestMsgEditWindowPrivate *priv = NULL;
2215         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2216
2217         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2218         if (!priv->update_caption_visibility)
2219                 return;
2220
2221         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2222         if (show)
2223                 gtk_widget_show (priv->bcc_caption);
2224         else
2225                 gtk_widget_hide (priv->bcc_caption);
2226
2227         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2228 }
2229
2230 static void
2231 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2232                                          ModestRecptEditor *editor)
2233 {
2234         ModestMsgEditWindowPrivate *priv;
2235
2236         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2237         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2238         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2239
2240         if (editor == NULL) {
2241                 GtkWidget *view_focus;
2242                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2243
2244                 /* This code should be kept in sync with ModestRecptEditor. The
2245                    textview inside the recpt editor is the one that really gets the
2246                    focus. As it's inside a scrolled window, and this one inside the
2247                    hbox recpt editor inherits from, we'll need to go up in the 
2248                    hierarchy to know if the text view is part of the recpt editor
2249                    or if it's a different text entry */
2250
2251                 if (gtk_widget_get_parent (view_focus)) {
2252                         GtkWidget *first_parent;
2253
2254                         first_parent = gtk_widget_get_parent (view_focus);
2255                         if (gtk_widget_get_parent (first_parent) && 
2256                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2257                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2258                         }
2259                 }
2260
2261                 if (editor == NULL)
2262                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2263
2264         }
2265
2266         modest_address_book_select_addresses (editor);
2267
2268 }
2269
2270 void
2271 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2272 {
2273         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2274
2275         modest_msg_edit_window_open_addressbook (window, NULL);
2276 }
2277
2278 static void
2279 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2280                                      gboolean show_toolbar)
2281 {
2282         ModestWindowPrivate *parent_priv;
2283         
2284         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2285         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2286
2287         /* FIXME: we can not just use the code of
2288            modest_msg_edit_window_setup_toolbar because it has a
2289            mixture of both initialization and creation code. */
2290
2291         if (show_toolbar)
2292                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2293         else
2294                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2295 }
2296
2297 void
2298 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2299                                            TnyHeaderFlags priority_flags)
2300 {
2301         ModestMsgEditWindowPrivate *priv;
2302         ModestWindowPrivate *parent_priv;
2303
2304         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2305
2306         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2307         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2308         priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2309
2310         if (priv->priority_flags != priority_flags) {
2311                 GtkAction *priority_action = NULL;
2312
2313                 priv->priority_flags = priority_flags;
2314
2315                 switch (priority_flags) {
2316                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2317                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2318                         gtk_widget_show (priv->priority_icon);
2319                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2320                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2321                         break;
2322                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2323                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2324                         gtk_widget_show (priv->priority_icon);
2325                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2326                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2327                         break;
2328                 default:
2329                         gtk_widget_hide (priv->priority_icon);
2330                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2331                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2332                         break;
2333                 }
2334                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2335                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2336         }
2337 }
2338
2339 void
2340 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2341                                         gint file_format)
2342 {
2343         ModestMsgEditWindowPrivate *priv;
2344         ModestWindowPrivate *parent_priv;
2345         gint current_format;
2346
2347         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2348
2349         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2350         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2351
2352         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2353                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2354
2355         if (current_format != file_format) {
2356                 switch (file_format) {
2357                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2358                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2359                         break;
2360                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2361                 {
2362                         GtkWidget *dialog;
2363                         gint response;
2364                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2365                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2366                         gtk_widget_destroy (dialog);
2367                         if (response == GTK_RESPONSE_OK) {
2368                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2369                         } else {
2370                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2371                                 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2372                         }
2373                 }
2374                         break;
2375                 }
2376                 update_dimmed (window);
2377         }
2378 }
2379
2380 void
2381 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2382 {
2383         GtkWidget *dialog;
2384         ModestMsgEditWindowPrivate *priv;
2385         WPTextBufferFormat oldfmt, fmt;
2386         gint old_position = 0;
2387         gint response = 0;
2388         gint position = 0;
2389         gint font_size;
2390         GdkColor *color = NULL;
2391         gboolean bold, bold_set, italic, italic_set;
2392         gboolean underline, underline_set;
2393         gboolean strikethrough, strikethrough_set;
2394         gboolean position_set;
2395         gboolean font_size_set, font_set, color_set;
2396         gchar *font_name;
2397
2398         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2399         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2400         
2401         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2402
2403         /* First we get the currently selected font information */
2404         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2405         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2406
2407         switch (oldfmt.text_position) {
2408         case TEXT_POSITION_NORMAL:
2409                 old_position = 0;
2410                 break;
2411         case TEXT_POSITION_SUPERSCRIPT:
2412                 old_position = 1;
2413                 break;
2414         default:
2415                 old_position = -1;
2416                 break;
2417         }
2418
2419         g_object_set (G_OBJECT (dialog),
2420                       "bold", oldfmt.bold != FALSE,
2421                       "bold-set", !oldfmt.cs.bold,
2422                       "underline", oldfmt.underline != FALSE,
2423                       "underline-set", !oldfmt.cs.underline,
2424                       "italic", oldfmt.italic != FALSE,
2425                       "italic-set", !oldfmt.cs.italic,
2426                       "strikethrough", oldfmt.strikethrough != FALSE,
2427                       "strikethrough-set", !oldfmt.cs.strikethrough,
2428                       "color", &oldfmt.color,
2429                       "color-set", !oldfmt.cs.color,
2430                       "size", wp_font_size[oldfmt.font_size],
2431                       "size-set", !oldfmt.cs.font_size,
2432                       "position", old_position,
2433                       "position-set", !oldfmt.cs.text_position,
2434                       "family", wp_get_font_name (oldfmt.font),
2435                       "family-set", !oldfmt.cs.font,
2436                       NULL);
2437
2438         gtk_widget_show_all (dialog);
2439         response = gtk_dialog_run (GTK_DIALOG (dialog));
2440         if (response == GTK_RESPONSE_OK) {
2441
2442                 g_object_get( dialog,
2443                               "bold", &bold,
2444                               "bold-set", &bold_set,
2445                               "underline", &underline,
2446                               "underline-set", &underline_set,
2447                               "italic", &italic,
2448                               "italic-set", &italic_set,
2449                               "strikethrough", &strikethrough,
2450                               "strikethrough-set", &strikethrough_set,
2451                               "color", &color,
2452                               "color-set", &color_set,
2453                               "size", &font_size,
2454                               "size-set", &font_size_set,
2455                               "family", &font_name,
2456                               "family-set", &font_set,
2457                               "position", &position,
2458                               "position-set", &position_set,
2459                               NULL );
2460                 
2461         }       
2462
2463         if (response == GTK_RESPONSE_OK) {
2464                 memset(&fmt, 0, sizeof(fmt));
2465                 if (bold_set) {
2466                         fmt.bold = bold;
2467                         fmt.cs.bold = TRUE;
2468                 }
2469                 if (italic_set) {
2470                         fmt.italic = italic;
2471                         fmt.cs.italic = TRUE;
2472                 }
2473                 if (underline_set) {
2474                         fmt.underline = underline;
2475                         fmt.cs.underline = TRUE;
2476                 }
2477                 if (strikethrough_set) {
2478                         fmt.strikethrough = strikethrough;
2479                         fmt.cs.strikethrough = TRUE;
2480                 }
2481                 if (position_set) {
2482                         fmt.text_position =
2483                                 ( position == 0 )
2484                                 ? TEXT_POSITION_NORMAL
2485                                 : ( ( position == 1 )
2486                                     ? TEXT_POSITION_SUPERSCRIPT
2487                                     : TEXT_POSITION_SUBSCRIPT );
2488                         fmt.cs.text_position = TRUE;
2489                 }
2490                 if (color_set) {
2491                         fmt.color = *color;
2492                         fmt.cs.color = TRUE;
2493                 }
2494                 if (font_set) {
2495                         fmt.font = wp_get_font_index(font_name,
2496                                                      DEFAULT_FONT);
2497                         fmt.cs.font = TRUE;
2498                 }
2499                 g_free(font_name);
2500                 if (font_size_set) {
2501                         fmt.font_size = wp_get_font_size_index(
2502                                 font_size, DEFAULT_FONT_SIZE);
2503                         fmt.cs.font_size = TRUE;
2504                 }
2505                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2506         }
2507         gtk_widget_destroy (dialog);
2508         
2509         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2510 }
2511
2512 void
2513 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2514 {
2515         ModestMsgEditWindowPrivate *priv;
2516
2517         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2518         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2519         
2520         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2521
2522         update_dimmed (window);
2523
2524 }
2525
2526 void
2527 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2528 {
2529         ModestMsgEditWindowPrivate *priv;
2530
2531         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2532         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2533         
2534         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2535
2536         update_dimmed (window);
2537
2538 }
2539
2540 static void
2541 update_dimmed (ModestMsgEditWindow *window)
2542 {
2543         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2544         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2545         GtkAction *action;
2546         GtkWidget *widget;
2547         gboolean rich_text;
2548         gboolean editor_focused;
2549
2550         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2551         editor_focused = gtk_widget_is_focus (priv->msg_body);
2552
2553         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2554         gtk_action_set_sensitive (action, rich_text && editor_focused);
2555 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2556 /*      gtk_action_set_sensitive (action, rich_text && editor_focused); */
2557         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2558         gtk_action_set_sensitive (action, rich_text && editor_focused);
2559         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2560         gtk_action_set_sensitive (action, rich_text && editor_focused);
2561         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2562         gtk_action_set_sensitive (action, rich_text && editor_focused);
2563         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2564         gtk_action_set_sensitive (action, rich_text && editor_focused);
2565         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2566         gtk_action_set_sensitive (action, rich_text && editor_focused);
2567         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2568         gtk_action_set_sensitive (action, rich_text && editor_focused);
2569         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2570         gtk_action_set_sensitive (action, rich_text && editor_focused);
2571         widget = priv->font_color_button;
2572         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2573         widget = priv->font_size_toolitem;
2574         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2575         widget = priv->font_face_toolitem;
2576         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2577 }
2578
2579 static void
2580 setup_insensitive_handlers (ModestMsgEditWindow *window)
2581 {
2582         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2583         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2584         GtkWidget *widget;
2585
2586         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2587         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2588         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2589         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2590         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2591         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2592         widget = priv->font_color_button;
2593         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2594         widget = priv->font_size_toolitem;
2595         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2596         widget = priv->font_face_toolitem;
2597         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2598
2599 }
2600
2601 static void  
2602 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2603 {
2604         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2605         GtkAction *action;
2606
2607         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2608         gtk_action_set_sensitive (action, can_undo);
2609 }
2610
2611 static void  
2612 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2613 {
2614         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2615         GtkAction *action;
2616
2617         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/RedoMenu");
2618         gtk_action_set_sensitive (action, can_redo);
2619 }
2620
2621 static void
2622 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2623 {
2624         GtkTextIter iter;
2625         GtkTextIter match_start, match_end;
2626
2627         if (image_id == NULL)
2628                 return;
2629
2630         gtk_text_buffer_get_start_iter (buffer, &iter);
2631
2632         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2633                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2634                 GSList *node;
2635                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2636                         GtkTextTag *tag = (GtkTextTag *) node->data;
2637                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2638                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2639                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2640                                         gint offset;
2641                                         offset = gtk_text_iter_get_offset (&match_start);
2642                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2643                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2644                                 }
2645                         }
2646                 }
2647                 gtk_text_iter_forward_char (&iter);
2648         }
2649 }
2650
2651 gboolean
2652 message_is_empty (ModestMsgEditWindow *window)
2653 {
2654         ModestMsgEditWindowPrivate *priv = NULL;
2655
2656         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2657         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2658
2659         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2660          * so we can ignore markup.
2661          */
2662         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2663         gint count = 0;
2664         if (buf)
2665                 count = gtk_text_buffer_get_char_count (buf);
2666
2667         return count == 0;
2668 }
2669
2670 static gboolean
2671 msg_body_focus (GtkWidget *focus,
2672                 GdkEventFocus *event,
2673                 gpointer userdata)
2674 {
2675         
2676         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2677         return FALSE;
2678 }
2679
2680 static void
2681 recpt_field_changed (GtkTextBuffer *buffer,
2682                   ModestMsgEditWindow *editor)
2683 {
2684         update_send_dimming (editor);
2685 }
2686
2687 static void
2688 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2689 {
2690         update_send_dimming (editor);
2691 }
2692
2693 static void  
2694 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2695 {
2696         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2697         const gchar *subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2698         if (message_is_empty(editor) || (subject == NULL || subject[0] == '\0')) {
2699                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_subject_or_body_not_modified"));
2700         } else {
2701                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2702         }
2703 }
2704
2705 static void
2706 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2707 {
2708         gboolean rich_text, editor_focused;
2709
2710         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2711         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2712         editor_focused = gtk_widget_is_focus (priv->msg_body);
2713
2714         if (!rich_text)
2715                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2716         else if (!editor_focused)
2717                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2718 }
2719
2720 static void
2721 reset_modified (ModestMsgEditWindow *editor)
2722 {
2723         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2724         GtkTextBuffer *buffer;
2725
2726         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2727         gtk_text_buffer_set_modified (buffer, FALSE);
2728         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2729         gtk_text_buffer_set_modified (buffer, FALSE);
2730         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2731         gtk_text_buffer_set_modified (buffer, FALSE);
2732         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2733 }
2734
2735 gboolean
2736 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2737 {
2738         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2739         GtkTextBuffer *buffer;
2740
2741         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2742         if (gtk_text_buffer_get_modified (buffer))
2743                 return TRUE;
2744         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2745         if (gtk_text_buffer_get_modified (buffer))
2746                 return TRUE;
2747         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2748         if (gtk_text_buffer_get_modified (buffer))
2749                 return TRUE;
2750         if (gtk_text_buffer_get_modified (priv->text_buffer))
2751                 return TRUE;
2752
2753         return FALSE;
2754 }
2755
2756
2757
2758
2759 gboolean
2760 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2761 {
2762         ModestMsgEditWindowPrivate *priv = NULL;
2763         
2764         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2765         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2766
2767         /* check if there's no recipient added */
2768         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2769             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2770             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2771                 /* no recipient contents, then select contacts */
2772                 modest_msg_edit_window_open_addressbook (window, NULL);
2773                 return FALSE;
2774         }
2775
2776         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
2777                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2778                 return FALSE;
2779         }
2780         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
2781                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2782                 return FALSE;
2783         }
2784         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2785                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2786                 return FALSE;
2787         }
2788
2789         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2790             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2791                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2792
2793         return TRUE;
2794
2795 }
2796
2797 static void
2798 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2799                                                ModestMsgEditWindow *window)
2800 {
2801         modest_msg_edit_window_offer_attach_file (window);
2802 }
2803
2804 static void
2805 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2806                                                GdkEvent *event,
2807                                                ModestMsgEditWindow *window)
2808 {
2809         if (!GTK_WIDGET_VISIBLE (window))
2810                 return;
2811
2812         update_remove_attachment_dimming (window);
2813         update_copy_cut_dimming (window);
2814         update_paste_dimming (window);
2815 }
2816
2817 static void 
2818 update_window_title (ModestMsgEditWindow *window)
2819 {
2820         ModestMsgEditWindowPrivate *priv = NULL;
2821         const gchar *subject;
2822
2823         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2824         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2825         if (subject == NULL || subject[0] == '\0')
2826                 subject = _("mail_va_new_email");
2827
2828         gtk_window_set_title (GTK_WINDOW (window), subject);
2829
2830 }
2831
2832 static void  
2833 subject_field_changed (GtkEditable *editable, 
2834                        ModestMsgEditWindow *window)
2835 {
2836         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2837         update_window_title (window);
2838         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2839         update_send_dimming (window);
2840 }
2841
2842 static void  
2843 subject_field_insert_text (GtkEditable *editable, 
2844                            gchar *new_text,
2845                            gint new_text_length,
2846                            gint *position,
2847                            ModestMsgEditWindow *window)
2848 {
2849         GString *result = g_string_new ("");
2850         gchar *current;
2851         gint result_len = 0;
2852
2853         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2854                 gunichar c = g_utf8_get_char_validated (current, 8);
2855                 /* Invalid unichar, stop */
2856                 if (c == -1)
2857                         break;
2858                 /* a bullet */
2859                 if (c == 0x2022)
2860                         continue;
2861                 result = g_string_append_unichar (result, c);
2862                 result_len++;
2863         }
2864
2865         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2866                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2867                 if (result_len > 0)
2868                 {
2869                         /* Prevent endless recursion */
2870                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2871                         g_signal_emit_by_name (editable, "insert-text", 
2872                                                (gpointer) result->str, (gpointer) result->len,
2873                                                (gpointer) position, (gpointer) window);
2874                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2875                 }
2876         }
2877         
2878         g_string_free (result, TRUE);
2879 }
2880
2881 void
2882 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2883                                             gboolean show)
2884 {
2885         ModestMsgEditWindowPrivate *priv = NULL;
2886
2887         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2888         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2889
2890         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2891
2892         if (show) {
2893                 gtk_widget_show_all (priv->find_toolbar);
2894                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2895         } else {
2896                 gtk_widget_hide_all (priv->find_toolbar);
2897                 gtk_widget_grab_focus (priv->msg_body);
2898         }
2899     
2900 }
2901
2902 static gboolean 
2903 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2904                                           const gchar *str,
2905                                           GtkTextIter *match_start,
2906                                           GtkTextIter *match_end)
2907 {
2908         GtkTextIter end_iter;
2909         gchar *str_casefold;
2910         gint str_chars_n;
2911         gchar *range_text;
2912         gchar *range_casefold;
2913         gint offset;
2914         gint range_chars_n;
2915         gboolean result = FALSE;
2916
2917         if (str == NULL)
2918                 return TRUE;
2919         
2920         /* get end iter */
2921         end_iter = *iter;
2922         gtk_text_iter_forward_to_end (&end_iter);
2923
2924         str_casefold = g_utf8_casefold (str, -1);
2925         str_chars_n = strlen (str);
2926
2927         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2928         range_casefold = g_utf8_casefold (range_text, -1);
2929         range_chars_n = strlen (range_casefold);
2930
2931         if (range_chars_n < str_chars_n) {
2932                 g_free (str_casefold);
2933                 g_free (range_text);
2934                 g_free (range_casefold);
2935                 return FALSE;
2936         }
2937
2938         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2939                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2940                 if (!g_utf8_collate (range_subtext, str_casefold)) {
2941                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2942                         result = TRUE;
2943                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2944                                                       match_start, match_end, NULL);
2945                         g_free (found_text);
2946                 }
2947                 g_free (range_subtext);
2948                 if (result)
2949                         break;
2950         }
2951         g_free (str_casefold);
2952         g_free (range_text);
2953         g_free (range_casefold);
2954
2955         return result;
2956 }
2957
2958
2959 static void 
2960 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2961                                             ModestMsgEditWindow *window)
2962 {
2963         gchar *current_search = NULL;
2964         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2965         gboolean result;
2966         GtkTextIter selection_start, selection_end;
2967         GtkTextIter match_start, match_end;
2968         gboolean continue_search = FALSE;
2969
2970         if (message_is_empty (window)) {
2971                 g_free (priv->last_search);
2972                 priv->last_search = NULL;
2973                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
2974                 return;
2975         }
2976
2977         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
2978         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
2979                 g_free (current_search);
2980                 g_free (priv->last_search);
2981                 priv->last_search = NULL;
2982                 /* Information banner about empty search */
2983                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
2984                 return;
2985         }
2986
2987         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
2988                 continue_search = TRUE;
2989         } else {
2990                 g_free (priv->last_search);
2991                 priv->last_search = g_strdup (current_search);
2992         }
2993
2994         if (continue_search) {
2995                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2996                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
2997                                                                    &match_start, &match_end);
2998                 if (!result)
2999                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3000         } else {
3001                 GtkTextIter buffer_start;
3002                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3003                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3004                                                                    &match_start, &match_end);
3005                 if (!result)
3006                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3007         }
3008
3009         /* Mark as selected the string found in search */
3010         if (result) {
3011                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3012                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3013         } else {
3014                 g_free (priv->last_search);
3015                 priv->last_search = NULL;
3016         }
3017         g_free (current_search);
3018 }
3019
3020 static void
3021 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3022                                            ModestMsgEditWindow *window)
3023 {
3024         GtkToggleAction *toggle;
3025         ModestWindowPrivate *parent_priv;
3026         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3027
3028         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3029         gtk_toggle_action_set_active (toggle, FALSE);
3030 }
3031
3032 static void 
3033 update_remove_attachment_dimming (ModestMsgEditWindow *window)
3034 {
3035         ModestWindowPrivate *parent_priv;
3036         ModestMsgEditWindowPrivate *priv;
3037         GtkAction *action;
3038         GList *selected_attachments = NULL;
3039         gint n_att_selected = 0;
3040
3041         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3042         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3043
3044         selected_attachments = modest_attachments_view_get_selection (
3045                         MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
3046         n_att_selected = g_list_length (selected_attachments);
3047         g_list_free (selected_attachments);
3048
3049         action = gtk_ui_manager_get_action (
3050                         parent_priv->ui_manager,
3051                         "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
3052         gtk_action_set_sensitive (action, n_att_selected == 1);
3053 }
3054
3055 static void 
3056 update_copy_cut_dimming (ModestMsgEditWindow *window)
3057 {
3058         ModestWindowPrivate *parent_priv = NULL;
3059         ModestMsgEditWindowPrivate *priv = NULL;
3060         GtkClipboard *clipboard = NULL;
3061         GtkAction *action = NULL;
3062         gboolean has_selection = FALSE;
3063         GtkWidget *focused = NULL;
3064         gchar *selection = NULL;
3065
3066         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3067         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3068         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3069         focused = gtk_window_get_focus (GTK_WINDOW (window));
3070
3071         has_selection = gtk_clipboard_wait_for_targets (clipboard, NULL, NULL);
3072
3073         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
3074         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3075         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
3076         gtk_action_set_sensitive (action, (has_selection) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
3077
3078         if (selection != NULL) 
3079                 g_free(selection);
3080 }
3081
3082 static void 
3083 update_paste_dimming (ModestMsgEditWindow *window)
3084 {
3085         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3086         GtkAction *action = NULL;
3087         GtkClipboard *clipboard = NULL;
3088         ModestEmailClipboard *e_clipboard;
3089         GtkWidget *focused;
3090         gboolean active;
3091
3092         focused = gtk_window_get_focus (GTK_WINDOW (window));
3093
3094         e_clipboard = modest_runtime_get_email_clipboard ();
3095         if (!modest_email_clipboard_cleared (e_clipboard)) {
3096                 active = TRUE;
3097         } else {
3098                 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3099                 active = gtk_clipboard_wait_is_text_available (clipboard);
3100         }
3101
3102         if (active) {
3103                 if (MODEST_IS_ATTACHMENTS_VIEW (focused))
3104                         active = FALSE;
3105         }
3106
3107         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
3108         gtk_action_set_sensitive (action, active);
3109
3110 }
3111
3112 static void 
3113 update_select_all_dimming (ModestMsgEditWindow *window)
3114 {
3115         GtkWidget *focused;
3116         gboolean dimmed = FALSE;
3117         GtkAction *action;
3118         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3119
3120         focused = gtk_window_get_focus (GTK_WINDOW (window));
3121         if (GTK_IS_ENTRY (focused)) {
3122                 const gchar *current_text;
3123                 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
3124                 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
3125         } else if (GTK_IS_TEXT_VIEW (focused)) {
3126                 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
3127                 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
3128         } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
3129                 dimmed = FALSE;
3130         }
3131         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
3132         gtk_action_set_sensitive (action, !dimmed);
3133 }
3134
3135 static void 
3136 update_zoom_dimming (ModestMsgEditWindow *window)
3137 {
3138         GtkWidget *focused;
3139         gboolean dimmed = FALSE;
3140         GtkAction *action;
3141         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3142
3143         focused = gtk_window_get_focus (GTK_WINDOW (window));
3144         dimmed = ! WP_IS_TEXT_VIEW (focused);
3145         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
3146         gtk_action_set_sensitive (action, !dimmed);
3147 }
3148
3149 static void
3150 update_send_dimming (ModestMsgEditWindow *window)
3151 {
3152         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3153         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3154         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
3155         const gchar *subject;
3156         gboolean dim = FALSE;
3157         GtkAction *action;
3158
3159         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
3160         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
3161         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
3162         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3163
3164         dim = ((gtk_text_buffer_get_char_count (to_buffer) +
3165                 gtk_text_buffer_get_char_count (cc_buffer) +
3166                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0)
3167           || (subject == NULL || subject[0] == '\0')
3168           || message_is_empty(window);
3169
3170         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
3171         gtk_action_set_sensitive (action, !dim);
3172         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
3173         gtk_action_set_sensitive (action, !dim);
3174 }
3175
3176 static void
3177 edit_menu_activated (GtkAction *action,
3178                      gpointer userdata)
3179 {
3180         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3181
3182         update_select_all_dimming (window);
3183         update_copy_cut_dimming (window);
3184         update_paste_dimming (window);
3185 }
3186 static void
3187 view_menu_activated (GtkAction *action,
3188                      gpointer userdata)
3189 {
3190         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3191
3192         update_zoom_dimming (window);
3193 }
3194
3195 gboolean 
3196 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3197 {
3198         ModestMsgEditWindowPrivate *priv;
3199
3200         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3201         return priv->sent;
3202 }
3203
3204 void 
3205 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3206                                  gboolean sent)
3207 {
3208         ModestMsgEditWindowPrivate *priv;
3209
3210         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3211         priv->sent = sent;
3212 }
3213
3214
3215 void            
3216 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3217                                   TnyMsg *draft)
3218 {
3219         ModestMsgEditWindowPrivate *priv;
3220         TnyHeader *header = NULL;
3221
3222         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3223         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3224
3225         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3226         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3227
3228         if (priv->draft_msg != NULL) {
3229                 header = tny_msg_get_header (priv->draft_msg);
3230                 if (TNY_IS_HEADER (header)) {
3231                         modest_window_mgr_unregister_header (mgr, header);
3232                 }
3233                 g_object_unref (priv->draft_msg);
3234         }
3235
3236         if (draft != NULL) {
3237                 g_object_ref (draft);
3238                 header = tny_msg_get_header (draft);
3239                 if (TNY_IS_HEADER (header))
3240                         modest_window_mgr_register_header (mgr, header);
3241                 if (priv->msg_uid) {
3242                         g_free (priv->msg_uid);
3243                         priv->msg_uid = NULL;
3244                 }
3245                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3246         }
3247
3248         priv->draft_msg = draft;
3249 }
3250
3251 static void  
3252 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3253                        GtkTextIter *start, GtkTextIter *end,
3254                        gpointer userdata)
3255 {
3256         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3257         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3258         gchar *tag_name;
3259
3260         if (tag == NULL+13) return;
3261         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3262         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3263                 replace_with_attachments (window, priv->attachments);
3264         }
3265 }
3266
3267 void                    
3268 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3269                                  TnyMimePart *part)
3270 {
3271         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3272
3273         g_return_if_fail (TNY_IS_MIME_PART (part));
3274         priv->attachments = g_list_prepend (priv->attachments, part);
3275         g_object_ref (part);
3276         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3277         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3278         gtk_widget_show_all (priv->attachments_caption);
3279         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3280 }
3281
3282 const gchar*    
3283 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3284 {
3285         ModestMsgEditWindowPrivate *priv;
3286
3287         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3288         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3289
3290         return priv->msg_uid;
3291 }