Fixes NB#76638
[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, (gpointer) (buffer_format->bold&0x1));
1624         }
1625         if (buffer_format->cs.italic) {
1626                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1627         }
1628         if (buffer_format->cs.color) {
1629                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1630         }
1631         if (buffer_format->cs.font_size) {
1632                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) (buffer_format->font_size));
1633         }
1634         if (buffer_format->cs.justification) {
1635                 switch (buffer_format->justification) {
1636                 case GTK_JUSTIFY_LEFT:
1637                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1638                         break;
1639                 case GTK_JUSTIFY_CENTER:
1640                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1641                         break;
1642                 case GTK_JUSTIFY_RIGHT:
1643                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1644                         break;
1645                 default:
1646                         break;
1647                 }
1648                         
1649         }
1650         if (buffer_format->cs.font) {
1651                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) (buffer_format->font));
1652         }
1653         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1654         if (buffer_format->cs.bullet) {
1655           wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((buffer_format->bullet)?1:0));
1656         }
1657 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1658
1659         g_free (current_format);
1660
1661 }
1662
1663 static void
1664 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1665 {
1666         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1667         GtkAction *action;
1668         ModestWindowPrivate *parent_priv;
1669         ModestMsgEditWindowPrivate *priv;
1670         GtkWidget *new_size_menuitem;
1671         GtkWidget *new_font_menuitem;
1672         
1673         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1674         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1675
1676         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1677                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1678                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1679                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1680         } else {
1681                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1682                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1683                         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1684         }
1685
1686         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1687
1688         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1689         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1690
1691         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1692         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1693
1694 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1695 /*      modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1696
1697         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1698                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1699                                          window);
1700         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1701         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1702                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1703                                            window);
1704
1705         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1706                                                       buffer_format->font_size))->data);
1707         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1708                 GtkWidget *label;
1709                 gchar *markup;
1710
1711                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1712                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1713                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1714                 g_free (markup);
1715                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1716                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1717                                                  window);
1718                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1719                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1720                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1721                                                    window);
1722         }
1723
1724         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1725                                                       buffer_format->font))->data);
1726         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1727                 GtkWidget *label;
1728                 gchar *markup;
1729
1730                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1731                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1732                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1733                 g_free (markup);
1734                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1735                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1736                                                  window);
1737                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1738                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1739                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1740                                                    window);
1741         }
1742
1743         g_free (buffer_format);
1744
1745 }
1746
1747 #ifdef MODEST_HILDON_VERSION_0
1748 void
1749 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1750 {
1751         
1752         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1753         ModestMsgEditWindowPrivate *priv;
1754         GtkWidget *dialog = NULL;
1755         gint response;
1756         GdkColor *new_color = NULL;
1757
1758         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1759         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1760         
1761         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1762         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1763         g_free (buffer_format);
1764
1765         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1766                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1767                 if (new_color != NULL) {
1768                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1769                                                       (gpointer) new_color);
1770                 }
1771         }
1772         gtk_widget_destroy (dialog);
1773 }
1774
1775
1776 void
1777 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1778 {
1779         
1780         ModestMsgEditWindowPrivate *priv;
1781         GtkWidget *dialog = NULL;
1782         gint response;
1783         GdkColor *old_color = NULL;
1784         const GdkColor *new_color = NULL;
1785         
1786         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1787         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1788         
1789         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1790         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1791
1792         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1793                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1794                 if (new_color != NULL)
1795                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1796         }
1797         gtk_widget_destroy (dialog);
1798
1799 }
1800
1801 #else 
1802 void
1803 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1804 {
1805         
1806         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1807         ModestMsgEditWindowPrivate *priv;
1808         GtkWidget *dialog = NULL;
1809
1810         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1811         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1812                 
1813         dialog = hildon_color_chooser_new ();
1814         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1815         g_free (buffer_format);
1816
1817         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1818                 GdkColor col;
1819                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1820                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1821                                               (gpointer) &col);
1822         }
1823         gtk_widget_destroy (dialog);
1824 }
1825
1826
1827 void
1828 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1829 {
1830         
1831         ModestMsgEditWindowPrivate *priv;
1832         GtkWidget *dialog = NULL;
1833         GdkColor *old_color = NULL;
1834         
1835         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1836         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1837         
1838         dialog = hildon_color_chooser_new ();
1839         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1840
1841         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
1842                 GdkColor col;
1843                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1844                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
1845         }
1846         gtk_widget_destroy (dialog);
1847 }
1848
1849 #endif /*!MODEST_HILDON_VERSION_0*/
1850
1851
1852
1853 static TnyStream* create_stream_for_uri (const gchar* uri)
1854 {
1855         if (!uri)
1856                 return NULL;
1857                 
1858         TnyStream *result = NULL;
1859
1860         GnomeVFSHandle *handle = NULL;
1861         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1862         if (test == GNOME_VFS_OK) {
1863                 /* Create the tinymail stream: */
1864                 /* Presumably tinymai will call gnome_vfs_close (handle) later. */
1865                 result = TNY_STREAM (tny_vfs_stream_new (handle));
1866         }
1867         
1868         return result;
1869 }
1870
1871 void
1872 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1873 {
1874         
1875         ModestMsgEditWindowPrivate *priv;
1876         GtkWidget *dialog = NULL;
1877         gint response = 0;
1878         GSList *uris = NULL;
1879         GSList *uri_node = NULL;
1880         
1881         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1882         
1883         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1884         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1885         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1886
1887         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1888
1889         response = gtk_dialog_run (GTK_DIALOG (dialog));
1890         switch (response) {
1891         case GTK_RESPONSE_OK:
1892                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1893                 break;
1894         default:
1895                 break;
1896         }
1897         gtk_widget_destroy (dialog);
1898
1899         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1900                 const gchar *uri;
1901                 GnomeVFSHandle *handle = NULL;
1902                 GnomeVFSResult result;
1903                 GtkTextIter position;
1904                 GtkTextMark *insert_mark;
1905
1906                 uri = (const gchar *) uri_node->data;
1907                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1908                 if (result == GNOME_VFS_OK) {
1909                         GdkPixbuf *pixbuf;
1910                         GnomeVFSFileInfo info;
1911                         gchar *filename, *basename, *escaped_filename;
1912                         TnyMimePart *mime_part;
1913                         gchar *content_id;
1914                         const gchar *mime_type = NULL;
1915                         GnomeVFSURI *vfs_uri;
1916
1917                         vfs_uri = gnome_vfs_uri_new (uri);
1918
1919                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
1920                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
1921                         g_free (escaped_filename);
1922                         gnome_vfs_uri_unref (vfs_uri);
1923
1924                         if (gnome_vfs_get_file_info (uri, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
1925                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
1926                             == GNOME_VFS_OK)
1927                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1928
1929                         mime_part = tny_platform_factory_new_mime_part
1930                                 (modest_runtime_get_platform_factory ());
1931                                 
1932                         TnyStream *stream = create_stream_for_uri (uri);
1933                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1934                         
1935                         content_id = g_strdup_printf ("%d", priv->last_cid);
1936                         tny_mime_part_set_content_id (mime_part, content_id);
1937                         g_free (content_id);
1938                         priv->last_cid++;
1939                         
1940                         basename = g_path_get_basename (filename);
1941                         tny_mime_part_set_filename (mime_part, basename);
1942                         g_free (basename);
1943
1944                         pixbuf = pixbuf_from_stream (stream, mime_type);
1945                         
1946                         if (pixbuf != NULL) {
1947                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1948                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1949                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1950                         } 
1951
1952                         priv->images = g_list_prepend (priv->images, mime_part);
1953                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1954                         g_free (filename);
1955
1956                 }
1957         }
1958
1959
1960 }
1961
1962 void
1963 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
1964 {       
1965         GtkWidget *dialog = NULL;
1966         gint response = 0;
1967         GSList *uris = NULL;
1968         GSList *uri_node;
1969         
1970         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1971         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
1972         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1973
1974         response = gtk_dialog_run (GTK_DIALOG (dialog));
1975         switch (response) {
1976         case GTK_RESPONSE_OK:
1977                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1978                 break;
1979         default:
1980                 break;
1981         }
1982         gtk_widget_destroy (dialog);
1983
1984         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1985                 const gchar *uri = (const gchar *) uri_node->data;
1986                 modest_msg_edit_window_attach_file_one (window, uri);
1987         }
1988         g_slist_foreach (uris, (GFunc) g_free, NULL);
1989         g_slist_free (uris);
1990 }
1991
1992 void
1993 modest_msg_edit_window_attach_file_one (
1994                 ModestMsgEditWindow *window,
1995                 const gchar *uri)
1996 {
1997         g_return_if_fail (window);
1998         g_return_if_fail (uri);
1999                 
2000         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2001         
2002         
2003         GnomeVFSHandle *handle = NULL;
2004         GnomeVFSResult result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2005         if (result == GNOME_VFS_OK) {
2006                 TnyMimePart *mime_part;
2007                 TnyStream *stream;
2008                 const gchar *mime_type = NULL;
2009                 gchar *basename;
2010                 gchar *escaped_filename;
2011                 gchar *filename;
2012                 gchar *content_id;
2013                 GnomeVFSFileInfo info;
2014                 GnomeVFSURI *vfs_uri;
2015
2016                 vfs_uri = gnome_vfs_uri_new (uri);
2017                 
2018
2019                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2020                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2021                 g_free (escaped_filename);
2022                 gnome_vfs_uri_unref (vfs_uri);
2023                 
2024                 if (gnome_vfs_get_file_info (uri, 
2025                                              &info, 
2026                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
2027                                              GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE)
2028                     == GNOME_VFS_OK)
2029                         mime_type = gnome_vfs_file_info_get_mime_type (&info);
2030                 mime_part = tny_platform_factory_new_mime_part
2031                         (modest_runtime_get_platform_factory ());
2032                 stream = TNY_STREAM (tny_vfs_stream_new (handle));
2033                 
2034                 tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
2035                 
2036                 content_id = g_strdup_printf ("%d", priv->last_cid);
2037                 tny_mime_part_set_content_id (mime_part, content_id);
2038                 g_free (content_id);
2039                 priv->last_cid++;
2040                 
2041                 basename = g_path_get_basename (filename);
2042                 tny_mime_part_set_filename (mime_part, basename);
2043                 g_free (basename);
2044                 
2045                 priv->attachments = g_list_prepend (priv->attachments, g_object_ref(mime_part));
2046                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2047                                                         mime_part);
2048                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2049                 gtk_widget_show_all (priv->attachments_caption);
2050                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2051                 g_free (filename);
2052         }
2053 }
2054
2055 void
2056 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2057                                           GList *att_list)
2058 {
2059         ModestMsgEditWindowPrivate *priv;
2060         gboolean clean_list = FALSE;
2061
2062         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2063         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2064
2065         if (att_list == NULL) {
2066                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2067                 clean_list = TRUE;
2068         }
2069
2070         if (att_list == NULL) {
2071                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2072         } else {
2073                 GtkWidget *confirmation_dialog = NULL;
2074                 gboolean dialog_response;
2075                 GList *node;
2076                 gchar *message = NULL;
2077                 gchar *filename = NULL;
2078
2079                 if (att_list->next == NULL) {
2080                         if (TNY_IS_MSG (att_list->data)) {
2081                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (att_list->data));
2082                                 if (header) {
2083                                         filename = g_strdup (tny_header_get_subject (header));
2084                                         g_object_unref (header);
2085                                 }
2086                                 if (filename == NULL) {
2087                                         filename = g_strdup (_("mail_va_no_subject"));
2088                                 }
2089                         } else {
2090                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (att_list->data)));
2091                         }
2092                 } else {
2093                         filename = g_strdup ("");
2094                 }
2095                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2096                                                     att_list->next == NULL), filename);
2097                 g_free (filename);
2098                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
2099                 g_free (message);
2100                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
2101                 gtk_widget_destroy (confirmation_dialog);
2102                 if (!dialog_response) {
2103                         if (clean_list)
2104                                 g_list_free (att_list);
2105                         return;
2106                 }
2107                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
2108
2109                 for (node = att_list; node != NULL; node = g_list_next (node)) {
2110                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
2111                         const gchar *att_id;
2112                         priv->attachments = g_list_remove (priv->attachments, mime_part);
2113
2114                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2115                                                                    mime_part);
2116                         if (priv->attachments == NULL)
2117                                 gtk_widget_hide (priv->attachments_caption);
2118                         att_id = tny_mime_part_get_content_id (mime_part);
2119                         if (att_id != NULL)
2120                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2121                                                                  att_id);
2122                         g_object_unref (mime_part);
2123                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2124                 }
2125         }
2126
2127         if (clean_list)
2128                 g_list_free (att_list);
2129 }
2130
2131 static void
2132 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2133                                             gpointer userdata)
2134 {
2135         ModestMsgEditWindowPrivate *priv;
2136         GdkColor *new_color;
2137         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2138         
2139 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2140         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2141 #else 
2142         GdkColor col;
2143         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2144         new_color = &col;
2145 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2146
2147         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2148         
2149         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2150
2151 }
2152
2153 static void
2154 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2155                                     gpointer userdata)
2156 {
2157         ModestMsgEditWindowPrivate *priv;
2158         gint new_size_index;
2159         ModestMsgEditWindow *window;
2160         GtkWidget *label;
2161         
2162         window = MODEST_MSG_EDIT_WINDOW (userdata);
2163         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2164         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2165
2166         if (gtk_check_menu_item_get_active (menu_item)) {
2167                 gchar *markup;
2168                 WPTextBufferFormat format;
2169
2170                 memset (&format, 0, sizeof (format));
2171                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2172
2173                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2174                 
2175                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2176                 format.cs.font_size = TRUE;
2177                 format.cs.text_position = TRUE;
2178                 format.cs.font = TRUE;
2179                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2180 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2181
2182                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2183                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
2184                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2185                 
2186                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2187                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2188                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2189                 g_free (markup);
2190         }
2191 }
2192
2193 static void
2194 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2195                                     gpointer userdata)
2196 {
2197         ModestMsgEditWindowPrivate *priv;
2198         gint new_font_index;
2199         ModestMsgEditWindow *window;
2200         GtkWidget *label;
2201         
2202         window = MODEST_MSG_EDIT_WINDOW (userdata);
2203         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2204         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2205
2206         if (gtk_check_menu_item_get_active (menu_item)) {
2207                 gchar *markup;
2208
2209                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2210                 
2211                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2212
2213                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2214                                                    (gpointer) new_font_index))
2215                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2216                 
2217                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2218                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2219                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2220                 g_free (markup);
2221         }
2222 }
2223
2224 static gboolean
2225 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2226 {
2227         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2228                 ModestWindowPrivate *parent_priv;
2229                 ModestWindowMgr *mgr;
2230                 gboolean is_fullscreen;
2231                 GtkAction *fs_toggle_action;
2232                 gboolean active;
2233
2234                 mgr = modest_runtime_get_window_mgr ();
2235                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2236
2237                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2238                 
2239                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2240                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2241                 if (is_fullscreen != active)
2242                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2243         }
2244
2245         return FALSE;
2246
2247 }
2248
2249 void
2250 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2251                                 gboolean show)
2252 {
2253         ModestMsgEditWindowPrivate *priv = NULL;
2254         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2255
2256         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2257         if (!priv->update_caption_visibility)
2258                 return;
2259
2260         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2261         if (show)
2262                 gtk_widget_show (priv->cc_caption);
2263         else
2264                 gtk_widget_hide (priv->cc_caption);
2265
2266         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2267 }
2268
2269 void
2270 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2271                                  gboolean show)
2272 {
2273         ModestMsgEditWindowPrivate *priv = NULL;
2274         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2275
2276         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2277         if (!priv->update_caption_visibility)
2278                 return;
2279
2280         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2281         if (show)
2282                 gtk_widget_show (priv->bcc_caption);
2283         else
2284                 gtk_widget_hide (priv->bcc_caption);
2285
2286         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2287 }
2288
2289 static void
2290 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2291                                          ModestRecptEditor *editor)
2292 {
2293         ModestMsgEditWindowPrivate *priv;
2294
2295         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2296         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2297         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2298
2299         if (editor == NULL) {
2300                 GtkWidget *view_focus;
2301                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2302
2303                 /* This code should be kept in sync with ModestRecptEditor. The
2304                    textview inside the recpt editor is the one that really gets the
2305                    focus. As it's inside a scrolled window, and this one inside the
2306                    hbox recpt editor inherits from, we'll need to go up in the 
2307                    hierarchy to know if the text view is part of the recpt editor
2308                    or if it's a different text entry */
2309
2310                 if (gtk_widget_get_parent (view_focus)) {
2311                         GtkWidget *first_parent;
2312
2313                         first_parent = gtk_widget_get_parent (view_focus);
2314                         if (gtk_widget_get_parent (first_parent) && 
2315                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2316                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2317                         }
2318                 }
2319
2320                 if (editor == NULL)
2321                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2322
2323         }
2324
2325         modest_address_book_select_addresses (editor);
2326
2327 }
2328
2329 void
2330 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2331 {
2332         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2333
2334         modest_msg_edit_window_open_addressbook (window, NULL);
2335 }
2336
2337 static void
2338 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2339                                      gboolean show_toolbar)
2340 {
2341         ModestWindowPrivate *parent_priv;
2342         const gchar *action_name;
2343         GtkAction *action;
2344         
2345         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2346         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2347
2348         /* We can not just use the code of
2349            modest_msg_edit_window_setup_toolbar because it has a
2350            mixture of both initialization and creation code. */
2351         if (show_toolbar)
2352                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2353         else
2354                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2355
2356         /* Update also the actions (to update the toggles in the
2357            menus), we have to do it manually because some other window
2358            of the same time could have changed it (remember that the
2359            toolbar fullscreen mode is shared by all the windows of the
2360            same type */
2361         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2362                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2363         else
2364                 action_name = "/MenuBar/ViewMenu/ShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2365         
2366         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2367         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2368                                                             show_toolbar);
2369
2370 }
2371
2372 void
2373 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2374                                            TnyHeaderFlags priority_flags)
2375 {
2376         ModestMsgEditWindowPrivate *priv;
2377         ModestWindowPrivate *parent_priv;
2378
2379         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2380
2381         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2382         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2383
2384         if (priv->priority_flags != priority_flags) {
2385                 GtkAction *priority_action = NULL;
2386
2387                 priv->priority_flags = priority_flags;
2388
2389                 switch (priority_flags) {
2390                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2391                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2392                         gtk_widget_show (priv->priority_icon);
2393                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2394                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2395                         break;
2396                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2397                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2398                         gtk_widget_show (priv->priority_icon);
2399                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2400                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2401                         break;
2402                 default:
2403                         gtk_widget_hide (priv->priority_icon);
2404                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2405                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2406                         break;
2407                 }
2408                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2409                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2410         }
2411 }
2412
2413 void
2414 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2415                                         gint file_format)
2416 {
2417         ModestMsgEditWindowPrivate *priv;
2418         ModestWindowPrivate *parent_priv;
2419         gint current_format;
2420
2421         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2422
2423         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2424         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2425
2426         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2427                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2428
2429         if (current_format != file_format) {
2430                 switch (file_format) {
2431                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2432                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2433                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2434                         break;
2435                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2436                 {
2437                         GtkWidget *dialog;
2438                         gint response;
2439                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2440                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2441                         gtk_widget_destroy (dialog);
2442                         if (response == GTK_RESPONSE_OK) {
2443                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2444                         } else {
2445                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu"));
2446                                 modest_maemo_toggle_action_set_active_block_notify (action, TRUE);
2447                         }
2448                 }
2449                         break;
2450                 }
2451                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2452         }
2453 }
2454
2455 void
2456 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2457 {
2458         GtkWidget *dialog;
2459         ModestMsgEditWindowPrivate *priv;
2460         WPTextBufferFormat oldfmt, fmt;
2461         gint old_position = 0;
2462         gint response = 0;
2463         gint position = 0;
2464         gint font_size;
2465         GdkColor *color = NULL;
2466         gboolean bold, bold_set, italic, italic_set;
2467         gboolean underline, underline_set;
2468         gboolean strikethrough, strikethrough_set;
2469         gboolean position_set;
2470         gboolean font_size_set, font_set, color_set;
2471         gchar *font_name;
2472
2473         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2474         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2475         
2476         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2477
2478         /* First we get the currently selected font information */
2479         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2480
2481         switch (oldfmt.text_position) {
2482         case TEXT_POSITION_NORMAL:
2483                 old_position = 0;
2484                 break;
2485         case TEXT_POSITION_SUPERSCRIPT:
2486                 old_position = 1;
2487                 break;
2488         default:
2489                 old_position = -1;
2490                 break;
2491         }
2492
2493         g_object_set (G_OBJECT (dialog),
2494                       "bold", oldfmt.bold != FALSE,
2495                       "bold-set", !oldfmt.cs.bold,
2496                       "underline", oldfmt.underline != FALSE,
2497                       "underline-set", !oldfmt.cs.underline,
2498                       "italic", oldfmt.italic != FALSE,
2499                       "italic-set", !oldfmt.cs.italic,
2500                       "strikethrough", oldfmt.strikethrough != FALSE,
2501                       "strikethrough-set", !oldfmt.cs.strikethrough,
2502                       "color", &oldfmt.color,
2503                       "color-set", !oldfmt.cs.color,
2504                       "size", wp_font_size[oldfmt.font_size],
2505                       "size-set", !oldfmt.cs.font_size,
2506                       "position", old_position,
2507                       "position-set", !oldfmt.cs.text_position,
2508                       "family", wp_get_font_name (oldfmt.font),
2509                       "family-set", !oldfmt.cs.font,
2510                       NULL);
2511
2512         gtk_widget_show_all (dialog);
2513         response = gtk_dialog_run (GTK_DIALOG (dialog));
2514         if (response == GTK_RESPONSE_OK) {
2515
2516                 g_object_get( dialog,
2517                               "bold", &bold,
2518                               "bold-set", &bold_set,
2519                               "underline", &underline,
2520                               "underline-set", &underline_set,
2521                               "italic", &italic,
2522                               "italic-set", &italic_set,
2523                               "strikethrough", &strikethrough,
2524                               "strikethrough-set", &strikethrough_set,
2525                               "color", &color,
2526                               "color-set", &color_set,
2527                               "size", &font_size,
2528                               "size-set", &font_size_set,
2529                               "family", &font_name,
2530                               "family-set", &font_set,
2531                               "position", &position,
2532                               "position-set", &position_set,
2533                               NULL );
2534                 
2535         }       
2536
2537         if (response == GTK_RESPONSE_OK) {
2538                 memset(&fmt, 0, sizeof(fmt));
2539                 if (bold_set) {
2540                         fmt.bold = bold;
2541                         fmt.cs.bold = TRUE;
2542                 }
2543                 if (italic_set) {
2544                         fmt.italic = italic;
2545                         fmt.cs.italic = TRUE;
2546                 }
2547                 if (underline_set) {
2548                         fmt.underline = underline;
2549                         fmt.cs.underline = TRUE;
2550                 }
2551                 if (strikethrough_set) {
2552                         fmt.strikethrough = strikethrough;
2553                         fmt.cs.strikethrough = TRUE;
2554                 }
2555                 if (position_set) {
2556                         fmt.text_position =
2557                                 ( position == 0 )
2558                                 ? TEXT_POSITION_NORMAL
2559                                 : ( ( position == 1 )
2560                                     ? TEXT_POSITION_SUPERSCRIPT
2561                                     : TEXT_POSITION_SUBSCRIPT );
2562                         fmt.cs.text_position = TRUE;
2563                 }
2564                 if (color_set) {
2565                         fmt.color = *color;
2566                         fmt.cs.color = TRUE;
2567                 }
2568                 if (font_set) {
2569                         fmt.font = wp_get_font_index(font_name,
2570                                                      DEFAULT_FONT);
2571                         fmt.cs.font = TRUE;
2572                 }
2573                 g_free(font_name);
2574                 if (font_size_set) {
2575                         fmt.font_size = wp_get_font_size_index(
2576                                 font_size, DEFAULT_FONT_SIZE);
2577                         fmt.cs.font_size = TRUE;
2578                 }
2579                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2580                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2581         }
2582         gtk_widget_destroy (dialog);
2583         
2584         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2585 }
2586
2587 void
2588 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2589 {
2590         ModestMsgEditWindowPrivate *priv;
2591
2592         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2593         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2594         
2595         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2596
2597         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2598
2599 }
2600
2601 void
2602 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2603 {
2604         ModestMsgEditWindowPrivate *priv;
2605
2606         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2607         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2608         
2609         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2610
2611         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2612
2613 }
2614
2615 static void  
2616 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2617 {
2618         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2619
2620         priv->can_undo = can_undo;
2621 }
2622
2623 static void  
2624 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2625 {
2626         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2627
2628         priv->can_redo = can_redo;
2629 }
2630
2631 gboolean            
2632 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2633 {
2634         ModestMsgEditWindowPrivate *priv;
2635         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2636         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2637
2638         return priv->can_undo;
2639 }
2640
2641 gboolean            
2642 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2643 {
2644         ModestMsgEditWindowPrivate *priv;
2645         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2646         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2647
2648         return priv->can_redo;
2649 }
2650
2651
2652 static void
2653 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2654 {
2655         GtkTextIter iter;
2656         GtkTextIter match_start, match_end;
2657
2658         if (image_id == NULL)
2659                 return;
2660
2661         gtk_text_buffer_get_start_iter (buffer, &iter);
2662
2663         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2664                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2665                 GSList *node;
2666                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2667                         GtkTextTag *tag = (GtkTextTag *) node->data;
2668                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2669                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2670                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2671                                         gint offset;
2672                                         offset = gtk_text_iter_get_offset (&match_start);
2673                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2674                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2675                                 }
2676                         }
2677                 }
2678                 gtk_text_iter_forward_char (&iter);
2679         }
2680 }
2681
2682 gboolean
2683 message_is_empty (ModestMsgEditWindow *window)
2684 {
2685         ModestMsgEditWindowPrivate *priv = NULL;
2686
2687         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2688         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2689
2690         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
2691          * so we can ignore markup.
2692          */
2693         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
2694         gint count = 0;
2695         if (buf)
2696                 count = gtk_text_buffer_get_char_count (buf);
2697
2698         return count == 0;
2699 }
2700
2701 static gboolean
2702 msg_body_focus (GtkWidget *focus,
2703                 GdkEventFocus *event,
2704                 gpointer userdata)
2705 {
2706         
2707         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
2708         return FALSE;
2709 }
2710
2711 static void
2712 recpt_field_changed (GtkTextBuffer *buffer,
2713                   ModestMsgEditWindow *editor)
2714 {
2715         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2716 }
2717
2718 static void
2719 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
2720 {
2721         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
2722 }
2723
2724 void
2725 modest_msg_edit_window_reset_modified (ModestMsgEditWindow *editor)
2726 {
2727         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2728         GtkTextBuffer *buffer;
2729
2730         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2731         gtk_text_buffer_set_modified (buffer, FALSE);
2732         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2733         gtk_text_buffer_set_modified (buffer, FALSE);
2734         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2735         gtk_text_buffer_set_modified (buffer, FALSE);
2736         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2737 }
2738
2739 gboolean
2740 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
2741 {
2742         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2743         GtkTextBuffer *buffer;
2744
2745         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2746         if (gtk_text_buffer_get_modified (buffer))
2747                 return TRUE;
2748         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2749         if (gtk_text_buffer_get_modified (buffer))
2750                 return TRUE;
2751         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2752         if (gtk_text_buffer_get_modified (buffer))
2753                 return TRUE;
2754         if (gtk_text_buffer_get_modified (priv->text_buffer))
2755                 return TRUE;
2756
2757         return FALSE;
2758 }
2759
2760
2761
2762
2763 gboolean
2764 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
2765 {
2766         ModestMsgEditWindowPrivate *priv = NULL;
2767         
2768         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2769         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2770
2771         /* check if there's no recipient added */
2772         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2773             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2774             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2775                 /* no recipient contents, then select contacts */
2776                 modest_msg_edit_window_open_addressbook (window, NULL);
2777                 return FALSE;
2778         }
2779
2780         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
2781                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2782                 return FALSE;
2783         }
2784         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
2785                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
2786                 return FALSE;
2787         }
2788         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
2789                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
2790                 return FALSE;
2791         }
2792
2793         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
2794             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
2795                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2796
2797         return TRUE;
2798
2799 }
2800
2801 static void
2802 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2803                                                ModestMsgEditWindow *window)
2804 {
2805         modest_msg_edit_window_offer_attach_file (window);
2806 }
2807
2808 const gchar *
2809 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
2810 {
2811         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
2812
2813         return priv->clipboard_text;
2814 }
2815
2816 static void
2817 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2818                                                GdkEvent *event,
2819                                                ModestMsgEditWindow *window)
2820 {
2821         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2822         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2823         gchar *text = NULL;
2824         if (!GTK_WIDGET_VISIBLE (window))
2825                 return;
2826
2827         text = gtk_clipboard_wait_for_text (selection_clipboard);
2828
2829         if (priv->clipboard_text != NULL) {
2830                 g_free (priv->clipboard_text);
2831         }
2832         priv->clipboard_text = text;
2833
2834         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2835 }
2836 static void 
2837 subject_field_move_cursor (GtkEntry *entry,
2838                            GtkMovementStep step,
2839                            gint a1,
2840                            gboolean a2,
2841                            gpointer window)
2842 {
2843         if (!GTK_WIDGET_VISIBLE (window))
2844                 return;
2845
2846         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2847 }
2848
2849 static void 
2850 update_window_title (ModestMsgEditWindow *window)
2851 {
2852         ModestMsgEditWindowPrivate *priv = NULL;
2853         const gchar *subject;
2854
2855         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2856         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2857         if (subject == NULL || subject[0] == '\0')
2858                 subject = _("mail_va_new_email");
2859
2860         gtk_window_set_title (GTK_WINDOW (window), subject);
2861
2862 }
2863
2864 static void  
2865 subject_field_changed (GtkEditable *editable, 
2866                        ModestMsgEditWindow *window)
2867 {
2868         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2869         update_window_title (window);
2870         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2871         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2872 }
2873
2874 static void  
2875 subject_field_insert_text (GtkEditable *editable, 
2876                            gchar *new_text,
2877                            gint new_text_length,
2878                            gint *position,
2879                            ModestMsgEditWindow *window)
2880 {
2881         GString *result = g_string_new ("");
2882         gchar *current;
2883         gint result_len = 0;
2884         const gchar *entry_text = NULL;
2885         gint old_length;
2886
2887         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
2888         old_length = g_utf8_strlen (entry_text, -1);
2889
2890         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
2891                 gunichar c = g_utf8_get_char_validated (current, 8);
2892                 /* Invalid unichar, stop */
2893                 if (c == -1)
2894                         break;
2895                 /* a bullet */
2896                 if (c == 0x2022)
2897                         continue;
2898                 result = g_string_append_unichar (result, c);
2899                 result_len++;
2900         }
2901
2902         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
2903                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
2904                 if (result_len > 0)
2905                 {
2906                         /* Prevent endless recursion */
2907                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2908                         g_signal_emit_by_name (editable, "insert-text", 
2909                                                (gpointer) result->str, (gpointer) result->len,
2910                                                (gpointer) position, (gpointer) window);
2911                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
2912                 }
2913         }
2914
2915         if (result_len + old_length > 1000) {
2916                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
2917                                                 dgettext("hildon-common-strings",
2918                                                          "ckdg_ib_maximum_characters_reached"));
2919         }
2920         
2921         g_string_free (result, TRUE);
2922 }
2923
2924 void
2925 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2926                                             gboolean show)
2927 {
2928         ModestMsgEditWindowPrivate *priv = NULL;
2929
2930         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2931         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2932
2933         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2934
2935         if (show) {
2936                 gtk_widget_show_all (priv->find_toolbar);
2937                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2938         } else {
2939                 gtk_widget_hide_all (priv->find_toolbar);
2940                 gtk_widget_grab_focus (priv->msg_body);
2941         }
2942     
2943 }
2944
2945 static gboolean 
2946 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
2947                                           const gchar *str,
2948                                           GtkTextIter *match_start,
2949                                           GtkTextIter *match_end)
2950 {
2951         GtkTextIter end_iter;
2952         gchar *str_casefold;
2953         gint str_chars_n;
2954         gchar *range_text;
2955         gchar *range_casefold;
2956         gint offset;
2957         gint range_chars_n;
2958         gboolean result = FALSE;
2959
2960         if (str == NULL)
2961                 return TRUE;
2962         
2963         /* get end iter */
2964         end_iter = *iter;
2965         gtk_text_iter_forward_to_end (&end_iter);
2966
2967         str_casefold = g_utf8_casefold (str, -1);
2968         str_chars_n = strlen (str);
2969
2970         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
2971         range_casefold = g_utf8_casefold (range_text, -1);
2972         range_chars_n = strlen (range_casefold);
2973
2974         if (range_chars_n < str_chars_n) {
2975                 g_free (str_casefold);
2976                 g_free (range_text);
2977                 g_free (range_casefold);
2978                 return FALSE;
2979         }
2980
2981         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
2982                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
2983                 if (!g_utf8_collate (range_subtext, str_casefold)) {
2984                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
2985                         result = TRUE;
2986                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
2987                                                       match_start, match_end, NULL);
2988                         g_free (found_text);
2989                 }
2990                 g_free (range_subtext);
2991                 if (result)
2992                         break;
2993         }
2994         g_free (str_casefold);
2995         g_free (range_text);
2996         g_free (range_casefold);
2997
2998         return result;
2999 }
3000
3001
3002 static void 
3003 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3004                                             ModestMsgEditWindow *window)
3005 {
3006         gchar *current_search = NULL;
3007         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3008         gboolean result;
3009         GtkTextIter selection_start, selection_end;
3010         GtkTextIter match_start, match_end;
3011         gboolean continue_search = FALSE;
3012
3013         if (message_is_empty (window)) {
3014                 g_free (priv->last_search);
3015                 priv->last_search = NULL;
3016                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3017                 return;
3018         }
3019
3020         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3021         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3022                 g_free (current_search);
3023                 g_free (priv->last_search);
3024                 priv->last_search = NULL;
3025                 /* Information banner about empty search */
3026                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3027                 return;
3028         }
3029
3030         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3031                 continue_search = TRUE;
3032         } else {
3033                 g_free (priv->last_search);
3034                 priv->last_search = g_strdup (current_search);
3035         }
3036
3037         if (continue_search) {
3038                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3039                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3040                                                                    &match_start, &match_end);
3041                 if (!result)
3042                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3043         } else {
3044                 GtkTextIter buffer_start;
3045                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3046                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3047                                                                    &match_start, &match_end);
3048                 if (!result)
3049                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3050         }
3051
3052         /* Mark as selected the string found in search */
3053         if (result) {
3054                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3055                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3056         } else {
3057                 g_free (priv->last_search);
3058                 priv->last_search = NULL;
3059         }
3060         g_free (current_search);
3061 }
3062
3063 static void
3064 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3065                                            ModestMsgEditWindow *window)
3066 {
3067         GtkToggleAction *toggle;
3068         ModestWindowPrivate *parent_priv;
3069         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3070
3071         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
3072         gtk_toggle_action_set_active (toggle, FALSE);
3073 }
3074
3075 gboolean 
3076 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3077 {
3078         ModestMsgEditWindowPrivate *priv;
3079
3080         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3081         return priv->sent;
3082 }
3083
3084 void 
3085 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3086                                  gboolean sent)
3087 {
3088         ModestMsgEditWindowPrivate *priv;
3089
3090         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3091         priv->sent = sent;
3092 }
3093
3094
3095 void            
3096 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3097                                   TnyMsg *draft)
3098 {
3099         ModestMsgEditWindowPrivate *priv;
3100         TnyHeader *header = NULL;
3101
3102         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3103         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3104
3105         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3106         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3107
3108         if (priv->draft_msg != NULL) {
3109                 g_object_unref (priv->draft_msg);
3110         }
3111
3112         if (draft != NULL) {
3113                 g_object_ref (draft);
3114                 header = tny_msg_get_header (draft);
3115                 if (priv->msg_uid) {
3116                         g_free (priv->msg_uid);
3117                         priv->msg_uid = NULL;
3118                 }
3119                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3120                 if (GTK_WIDGET_REALIZED (window))
3121                         modest_window_mgr_register_window (mgr, MODEST_WINDOW (window));
3122         }
3123
3124         priv->draft_msg = draft;
3125 }
3126
3127 static void  
3128 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3129                        GtkTextIter *start, GtkTextIter *end,
3130                        gpointer userdata)
3131 {
3132         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3133         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3134         gchar *tag_name;
3135
3136         if (tag == NULL+13) return;
3137         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3138         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3139                 replace_with_images (window, priv->images);
3140         }
3141 }
3142
3143 void                    
3144 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3145                                  TnyMimePart *part)
3146 {
3147         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3148
3149         g_return_if_fail (TNY_IS_MIME_PART (part));
3150         priv->attachments = g_list_prepend (priv->attachments, part);
3151         g_object_ref (part);
3152         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part);
3153         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3154         gtk_widget_show_all (priv->attachments_caption);
3155         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3156 }
3157
3158 const gchar*    
3159 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3160 {
3161         ModestMsgEditWindowPrivate *priv;
3162
3163         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3164         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3165
3166         return priv->msg_uid;
3167 }
3168
3169 GtkWidget *
3170 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3171                                          ModestMsgEditWindowWidgetType widget_type)
3172 {
3173         ModestMsgEditWindowPrivate *priv;
3174
3175         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3176         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3177
3178         switch (widget_type) {
3179         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3180                 return priv->msg_body;
3181                 break;
3182         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3183                 return priv->to_field;
3184                 break;
3185         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3186                 return priv->cc_field;
3187                 break;
3188         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3189                 return priv->bcc_field;
3190                 break;
3191         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3192                 return priv->subject_field;
3193                 break;
3194         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3195                 return priv->attachments_view;
3196                 break;
3197         default:
3198                 return NULL;
3199         }
3200 }
3201
3202 static void 
3203 remove_tags (WPTextBuffer *buffer)
3204 {
3205         GtkTextIter start, end;
3206
3207         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3208         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3209
3210         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3211 }
3212
3213 static void
3214 on_account_removed (TnyAccountStore *account_store, 
3215                     TnyAccount *account,
3216                     gpointer user_data)
3217 {
3218         /* Do nothing if it's a store account, because we use the
3219            transport to send the messages */
3220         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3221                 const gchar *parent_acc = NULL;
3222                 const gchar *our_acc = NULL;
3223
3224                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3225                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3226                 /* Close this window if I'm showing a message of the removed account */
3227                 if (strcmp (parent_acc, our_acc) == 0)
3228                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3229         }
3230 }
3231
3232 static gboolean
3233 on_zoom_minus_plus_not_implemented (ModestWindow *window)
3234 {
3235         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3236
3237         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
3238         return FALSE;
3239
3240 }