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