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