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