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