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