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