889e6114e48db27e9fe2c66fb8364d73315a3571
[modest] / src / hildon2 / 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 #include <tny-camel-mem-stream.h>
39
40 #include <config.h>
41
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
44
45 #include <widgets/modest-msg-edit-window.h>
46 #include <modest-selector-picker.h>
47 #include <widgets/modest-recpt-editor.h>
48 #include <widgets/modest-attachments-view.h>
49
50 #include <modest-runtime.h>
51
52 #include "modest-platform.h"
53 #include "modest-icon-names.h"
54 #include "modest-widget-memory.h"
55 #include "modest-window-priv.h"
56 #include "modest-mail-operation.h"
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-tny-folder.h"
60 #include "modest-tny-account.h"
61 #include "modest-address-book.h"
62 #include "modest-text-utils.h"
63 #include <tny-simple-list.h>
64 #include <wptextview.h>
65 #include <wptextbuffer.h>
66 #include <hildon/hildon-pannable-area.h>
67 #include "modest-msg-edit-window-ui-dimming.h"
68
69 #include "modest-hildon-includes.h"
70 #ifdef MODEST_HAVE_HILDON0_WIDGETS
71 #include <hildon-widgets/hildon-color-chooser.h>
72 #endif
73 #include "widgets/modest-msg-edit-window-ui.h"
74 #ifdef MODEST_HAVE_HILDON0_WIDGETS
75 #include <libgnomevfs/gnome-vfs-mime-utils.h>
76 #else
77 #include <libgnomevfs/gnome-vfs-mime.h>
78 #endif
79 #include <modest-utils.h>
80 #include "modest-maemo-utils.h"
81 #include <modest-ui-constants.h>
82
83
84 #define DEFAULT_FONT_SIZE 3
85 #define DEFAULT_FONT 2
86 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
87 #define DEFAULT_MAIN_VBOX_SPACING 6
88 #define SUBJECT_MAX_LENGTH 1000
89 #define IMAGE_MAX_WIDTH 560
90 #define DEFAULT_FONT_SCALE 1.5
91
92 static gboolean is_wp_text_buffer_started = FALSE;
93
94 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
95 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
96 static void  modest_msg_edit_window_finalize     (GObject *obj);
97
98 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
99 static void  body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
100 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
101
102 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
103 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
104 static void  text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window);
105 static void  text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
106                                     GtkTextIter *start, GtkTextIter *end,
107                                     gpointer userdata);
108 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
109 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
110 static void  subject_field_insert_text (GtkEditable *editable, 
111                                         gchar *new_text,
112                                         gint new_text_length,
113                                         gint *position,
114                                         ModestMsgEditWindow *window);
115 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
116                                                          gpointer userdata);
117 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
118                                                  gpointer userdata);
119 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
120                                                  gpointer userdata);
121 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
122
123 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
124                                                      ModestRecptEditor *editor);
125 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
126                                                            ModestMsgEditWindow *window);
127
128 /* ModestWindow methods implementation */
129 static void modest_msg_edit_window_disconnect_signals (ModestWindow *window);
130 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
131                                                    gboolean show_toolbar);
132 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
133                                                            GdkEvent *event,
134                                                            ModestMsgEditWindow *window);
135 static void modest_msg_edit_window_clipboard_owner_handle_change_in_idle (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 void init_window (ModestMsgEditWindow *obj);
160
161 gboolean scroll_drag_timeout (gpointer userdata);
162 static void correct_scroll (ModestMsgEditWindow *w);
163 static void correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused);
164 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
165                                          ModestMsgEditWindow *userdata);
166 static void text_buffer_mark_set (GtkTextBuffer *buffer,
167                                   GtkTextIter *iter,
168                                   GtkTextMark *mark,
169                                   ModestMsgEditWindow *userdata);
170 static void on_message_settings (GtkAction *action,
171                                  ModestMsgEditWindow *window);
172 static void setup_menu (ModestMsgEditWindow *self);
173
174 static void DEBUG_BUFFER (WPTextBuffer *buffer)
175 {
176 #ifdef DEBUG
177         GtkTextIter iter;
178         g_message ("BEGIN BUFFER OF SIZE %d", gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)));
179
180         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter);
181         while (!gtk_text_iter_is_end (&iter)) {
182                 GString *output = g_string_new ("");
183                 GSList *toggled_tags;
184                 GSList *node;
185
186                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);
187                 g_string_append_printf (output, "%d: CLOSED [ ", gtk_text_iter_get_offset (&iter));
188                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
189                         GtkTextTag *tag = (GtkTextTag *) node->data;
190                         const gchar *name;
191                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
192                         output = g_string_append (output, name);
193                         g_string_append (output, " ");
194                 }
195                 output = g_string_append (output, "] OPENED [ ");
196                 toggled_tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);
197                 for (node = toggled_tags; node != NULL; node = g_slist_next (node)) {
198                         GtkTextTag *tag = (GtkTextTag *) node->data;
199                         const gchar *name;
200                         g_object_get (G_OBJECT (tag), "name", &name, NULL);
201                         output = g_string_append (output, name);
202                         g_string_append (output, " ");
203                 }
204                 output = g_string_append (output, "]\n");
205                 g_message ("%s", output->str);
206                 g_string_free (output, TRUE);
207                 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
208         }
209         g_message ("END BUFFER");
210 #endif
211 }
212
213 static const GtkActionEntry hildon2_msg_edit_action_entries [] = {
214         { "MessageSettings", NULL, N_("TODO: settings..."), NULL, NULL, G_CALLBACK (on_message_settings)},
215 };
216
217
218 /* static gboolean */
219 /* on_key_pressed (GtkWidget *self, */
220 /*              GdkEventKey *event, */
221 /*              gpointer user_data); */
222
223 /* list my signals */
224 enum {
225         /* MY_SIGNAL_1, */
226         /* MY_SIGNAL_2, */
227         LAST_SIGNAL
228 };
229
230 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
231 struct _ModestMsgEditWindowPrivate {
232         GtkWidget   *msg_body;
233         GtkWidget   *frame;
234         GtkWidget   *header_box;
235         
236         ModestPairList *from_field_protos;
237         GtkWidget   *from_field;
238         gchar       *original_account_name;
239         
240         GtkWidget   *to_field;
241         GtkWidget   *cc_field;
242         GtkWidget   *bcc_field;
243         GtkWidget   *subject_field;
244         GtkWidget   *attachments_view;
245         GtkWidget   *priority_icon;
246         GtkWidget   *add_attachment_button;
247
248         GtkWidget   *cc_caption;
249         GtkWidget   *bcc_caption;
250         gboolean     update_caption_visibility;
251         GtkWidget   *attachments_caption;
252
253         GtkTextBuffer *text_buffer;
254
255         GtkWidget   *font_size_toolitem;
256         GtkWidget   *font_face_toolitem;
257         GtkWidget   *font_color_button;
258         GtkWidget   *font_color_toolitem;
259         GSList      *font_items_group;
260         GtkWidget   *font_tool_button_label;
261         GSList      *size_items_group;
262         GtkWidget   *size_tool_button_label;
263         
264         GtkWidget   *find_toolbar;
265         gchar       *last_search;
266
267         GtkWidget   *font_dialog;
268
269         GtkWidget   *pannable;
270         guint        scroll_drag_timeout_id;
271         gdouble      last_upper;
272
273         gint next_cid;
274         TnyList *attachments;
275         TnyList *images;
276         guint64 images_size;
277         gint images_count;
278
279         TnyHeaderFlags priority_flags;
280         
281         gboolean    can_undo, can_redo;
282         gulong      clipboard_change_handler_id;
283         gulong      default_clipboard_change_handler_id;
284         gulong      account_removed_handler_id;
285         guint       clipboard_owner_idle;
286         gchar       *clipboard_text;
287
288         TnyMsg      *draft_msg;
289         TnyMsg      *outbox_msg;
290         gchar       *msg_uid;
291
292         gboolean    sent;
293
294         GtkWidget   *app_menu;
295         GtkWidget   *cc_button;
296         GtkWidget   *bcc_button;
297         GtkWidget   *find_toolbar_button;
298 };
299
300 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
301                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
302                                                     ModestMsgEditWindowPrivate))
303 /* globals */
304 static GtkWindowClass *parent_class = NULL;
305
306 /* uncomment the following if you have defined any signals */
307 /* static guint signals[LAST_SIGNAL] = {0}; */
308
309 GType
310 modest_msg_edit_window_get_type (void)
311 {
312         static GType my_type = 0;
313         if (!my_type) {
314                 static const GTypeInfo my_info = {
315                         sizeof(ModestMsgEditWindowClass),
316                         NULL,           /* base init */
317                         NULL,           /* base finalize */
318                         (GClassInitFunc) modest_msg_edit_window_class_init,
319                         NULL,           /* class finalize */
320                         NULL,           /* class data */
321                         sizeof(ModestMsgEditWindow),
322                         1,              /* n_preallocs */
323                         (GInstanceInitFunc) modest_msg_edit_window_init,
324                         NULL
325                 };
326                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
327                                                   "ModestMsgEditWindow",
328                                                   &my_info, 0);
329
330         }
331         return my_type;
332 }
333
334 static void
335 save_state (ModestWindow *self)
336 {
337         modest_widget_memory_save (modest_runtime_get_conf(),
338                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
339 }
340
341
342 static void
343 restore_settings (ModestMsgEditWindow *self)
344 {
345         ModestConf *conf = NULL;
346         GtkAction *action;
347         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
348
349         conf = modest_runtime_get_conf ();
350
351         /* Dim at start clipboard actions */
352         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
353         gtk_action_set_sensitive (action, FALSE);
354         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
355         gtk_action_set_sensitive (action, FALSE);
356         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
357         gtk_action_set_sensitive (action, FALSE);
358
359         modest_widget_memory_restore (conf, G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
360 }
361
362
363 static void
364 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
365 {
366         GObjectClass *gobject_class;
367         ModestWindowClass *modest_window_class;
368         gobject_class = (GObjectClass*) klass;
369         modest_window_class = (ModestWindowClass*) klass;
370
371         parent_class            = g_type_class_peek_parent (klass);
372         gobject_class->finalize = modest_msg_edit_window_finalize;
373
374         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
375         modest_window_class->save_state_func = save_state;
376         modest_window_class->disconnect_signals_func = modest_msg_edit_window_disconnect_signals;
377
378         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
379 }
380
381 static void
382 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
383 {
384         ModestMsgEditWindowPrivate *priv;
385         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
386
387         priv->msg_body      = NULL;
388         priv->frame         = NULL;
389         priv->from_field    = NULL;
390         priv->to_field      = NULL;
391         priv->cc_field      = NULL;
392         priv->bcc_field     = NULL;
393         priv->subject_field = NULL;
394         priv->attachments   = TNY_LIST (tny_simple_list_new ());
395         priv->images        = TNY_LIST (tny_simple_list_new ());
396         priv->images_size   = 0;
397         priv->images_count  = 0;
398         priv->next_cid      = 0;
399
400         priv->cc_caption    = NULL;
401         priv->bcc_caption    = NULL;
402         priv->update_caption_visibility = FALSE;
403
404         priv->priority_flags = 0;
405
406         priv->find_toolbar = NULL;
407         priv->last_search = NULL;
408
409         priv->draft_msg = NULL;
410         priv->outbox_msg = NULL;
411         priv->msg_uid = NULL;
412
413         priv->can_undo = FALSE;
414         priv->can_redo = FALSE;
415         priv->clipboard_change_handler_id = 0;
416         priv->default_clipboard_change_handler_id = 0;
417         priv->account_removed_handler_id = 0;
418         priv->clipboard_owner_idle = 0;
419         priv->clipboard_text = NULL;
420         priv->sent = FALSE;
421
422         priv->scroll_drag_timeout_id = 0;
423         priv->last_upper = 0.0;
424
425         priv->font_dialog = NULL;
426         priv->app_menu = NULL;
427
428         if (!is_wp_text_buffer_started) {
429                 is_wp_text_buffer_started = TRUE;
430                 wp_text_buffer_library_init ();
431         }
432
433         init_window (obj);
434         
435         hildon_program_add_window (hildon_program_get_instance(),
436                                    HILDON_WINDOW(obj));
437 }
438
439
440 /** 
441  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
442  */
443 static ModestPairList*
444 get_transports (void)
445 {
446         GSList *transports = NULL;
447         
448         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
449         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
450                                                              TRUE /* only enabled accounts. */); 
451                                                 
452         GSList *cursor = accounts;
453         while (cursor) {
454                 gchar *account_name = cursor->data;
455                 gchar *from_string  = NULL;
456                 if (account_name) {
457                         from_string = modest_account_mgr_get_from_string (account_mgr,
458                                                                           account_name);
459                 }
460                 
461                 if (from_string && account_name) {
462                         gchar *name = account_name;
463                         ModestPair *pair = modest_pair_new ((gpointer) name,
464                                                 (gpointer) from_string , TRUE);
465                         transports = g_slist_prepend (transports, pair);
466                 }
467                 
468                 cursor = cursor->next;
469         }
470         g_slist_free (accounts); /* only free the accounts, not the elements,
471                                   * because they are used in the pairlist */
472         return transports;
473 }
474
475 static void window_focus (GtkWindow *window,
476                           GtkWidget *widget,
477                           gpointer userdata)
478 {
479         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
480 }
481
482 gboolean
483 scroll_drag_timeout (gpointer userdata)
484 {
485         ModestMsgEditWindow *win = (ModestMsgEditWindow *) userdata;
486         ModestMsgEditWindowPrivate *priv;
487
488         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(win);
489
490         correct_scroll_without_drag_check (win, TRUE);
491
492         priv->scroll_drag_timeout_id = 0;
493
494         return FALSE;
495 }
496
497 static void
498 correct_scroll_without_drag_check (ModestMsgEditWindow *w, gboolean only_if_focused)
499 {
500         ModestMsgEditWindowPrivate *priv;
501         GtkTextMark *insert;
502         GtkTextIter iter;
503         GdkRectangle rectangle;
504         gdouble new_value;
505         gint offset;
506
507         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
508
509         if (only_if_focused && !gtk_widget_is_focus (priv->msg_body))
510                 return;
511
512         insert = gtk_text_buffer_get_insert (priv->text_buffer);
513         gtk_text_buffer_get_iter_at_mark (priv->text_buffer, &iter, insert);
514
515         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &iter, &rectangle);
516         offset = priv->msg_body->allocation.y;
517
518         new_value = (offset + rectangle.y);
519
520         hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (priv->pannable), -1, new_value);
521 }
522
523 static void
524 correct_scroll (ModestMsgEditWindow *w)
525 {
526         ModestMsgEditWindowPrivate *priv;
527
528         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(w);
529         if (gtk_grab_get_current () == priv->msg_body) {
530                 if (priv->scroll_drag_timeout_id == 0) {
531                         priv->scroll_drag_timeout_id = g_timeout_add (500, (GSourceFunc) scroll_drag_timeout,
532                                                                       (gpointer) w);
533                 }
534                 return;
535         }
536
537         correct_scroll_without_drag_check (w, TRUE);
538 }
539
540 static void
541 text_buffer_end_user_action (GtkTextBuffer *buffer,
542                              ModestMsgEditWindow *userdata)
543 {
544
545         correct_scroll (userdata);
546 }
547
548 static void
549 text_buffer_mark_set (GtkTextBuffer *buffer,
550                       GtkTextIter *iter,
551                       GtkTextMark *mark,
552                       ModestMsgEditWindow *userdata)
553 {
554         gtk_text_buffer_begin_user_action (buffer);
555         gtk_text_buffer_end_user_action (buffer);
556 }
557
558 static void
559 cut_clipboard_check (GtkTextView *text_view,
560                      gpointer userdata)
561 {
562         GtkTextBuffer *buffer;
563         
564         buffer = gtk_text_view_get_buffer (text_view);
565         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
566                 g_signal_stop_emission_by_name ((gpointer )text_view, "cut-clipboard");
567         }
568 }
569
570 static void
571 copy_clipboard_check (GtkTextView *text_view,
572                      gpointer userdata)
573 {
574         GtkTextBuffer *buffer;
575         
576         buffer = gtk_text_view_get_buffer (text_view);
577         if (!modest_text_utils_buffer_selection_is_valid (buffer)) {
578                 g_signal_stop_emission_by_name ((gpointer )text_view, "copy-clipboard");
579         }
580 }
581
582 static void
583 attachment_deleted (ModestAttachmentsView *attachments_view,
584                     gpointer user_data)
585 {
586         modest_msg_edit_window_remove_attachments (MODEST_MSG_EDIT_WINDOW (user_data),
587                                                    NULL);
588 }
589
590 static void
591 connect_signals (ModestMsgEditWindow *obj)
592 {
593         ModestMsgEditWindowPrivate *priv;
594
595         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
596
597         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
598                           G_CALLBACK (text_buffer_refresh_attributes), obj);
599         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
600                           G_CALLBACK (text_buffer_can_undo), obj);
601         g_signal_connect (G_OBJECT (priv->text_buffer), "can-redo",
602                           G_CALLBACK (text_buffer_can_redo), obj);
603         g_signal_connect (G_OBJECT (priv->text_buffer), "changed",
604                           G_CALLBACK (body_changed), obj);
605         g_signal_connect (G_OBJECT (priv->text_buffer), "modified-changed",
606                           G_CALLBACK (body_changed), obj);
607         g_signal_connect (G_OBJECT (priv->text_buffer), "end-user-action",
608                           G_CALLBACK (text_buffer_end_user_action), obj);
609         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
610                           G_CALLBACK (text_buffer_mark_set), obj);
611         g_signal_connect_after (G_OBJECT (priv->text_buffer), "apply-tag",
612                                 G_CALLBACK (text_buffer_apply_tag), obj);
613         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
614                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
615         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
616                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
617         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
618                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
619
620         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
621                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
622
623         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
624                           G_CALLBACK (msg_body_focus), obj);
625         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
626                           G_CALLBACK (msg_body_focus), obj);
627         g_signal_connect (G_OBJECT (obj), "set-focus", G_CALLBACK (window_focus), obj);
628         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
629                           "changed", G_CALLBACK (recpt_field_changed), obj);
630         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
631                           "changed", G_CALLBACK (recpt_field_changed), obj);
632         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
633                           "changed", G_CALLBACK (recpt_field_changed), obj);
634         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
635         g_signal_connect_after (G_OBJECT (priv->subject_field), "move-cursor", G_CALLBACK (subject_field_move_cursor), obj);
636         g_signal_connect (G_OBJECT (priv->subject_field), "insert-text", G_CALLBACK (subject_field_insert_text), obj);
637
638         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
639         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
640
641         priv->clipboard_change_handler_id = 
642                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
643                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
644         priv->default_clipboard_change_handler_id = 
645                 g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
646                                   G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
647
648         g_signal_connect (G_OBJECT (priv->msg_body), "cut-clipboard", G_CALLBACK (cut_clipboard_check), NULL);
649         g_signal_connect (G_OBJECT (priv->msg_body), "copy-clipboard", G_CALLBACK (copy_clipboard_check), NULL);
650         g_signal_connect (G_OBJECT (priv->attachments_view), "delete", G_CALLBACK (attachment_deleted), obj);
651 }
652
653 static void
654 init_wp_text_view_style ()
655 {
656         static gboolean initialized = FALSE;
657
658         if (!initialized) {
659                 gtk_rc_parse_string ("class \"WPTextView\" style \"fremantle-textview\"");
660                 initialized = TRUE;
661         }
662 }       
663
664 static void
665 init_window (ModestMsgEditWindow *obj)
666 {
667         GtkWidget *to_caption, *subject_caption;
668         GtkWidget *main_vbox;
669         ModestMsgEditWindowPrivate *priv;
670         GtkActionGroup *action_group;
671         ModestWindowPrivate *parent_priv;
672         GdkPixbuf *window_icon = NULL;
673         GError *error = NULL;
674
675         GtkSizeGroup *title_size_group;
676         GtkSizeGroup *value_size_group;
677         GtkWidget *subject_box;
678         GtkWidget *attachment_icon;
679         GtkWidget *window_box;
680 #if (GTK_MINOR_VERSION >= 10)
681         GdkAtom deserialize_type;
682 #endif
683
684         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
685         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
686
687         parent_priv->ui_manager = gtk_ui_manager_new();
688         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
689         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
690
691         /* Add common actions */
692         gtk_action_group_add_actions (action_group,
693                                       modest_msg_edit_action_entries,
694                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
695                                       obj);
696         gtk_action_group_add_actions (action_group,
697                                       hildon2_msg_edit_action_entries,
698                                       G_N_ELEMENTS (hildon2_msg_edit_action_entries),
699                                       obj);
700         gtk_action_group_add_toggle_actions (action_group,
701                                              modest_msg_edit_toggle_action_entries,
702                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
703                                              obj);
704         gtk_action_group_add_radio_actions (action_group,
705                                             modest_msg_edit_alignment_radio_action_entries,
706                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
707                                             GTK_JUSTIFY_LEFT,
708                                             G_CALLBACK (modest_ui_actions_on_change_justify),
709                                             obj);
710         gtk_action_group_add_radio_actions (action_group,
711                                             modest_msg_edit_priority_action_entries,
712                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
713                                             0,
714                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
715                                             obj);
716         gtk_action_group_add_radio_actions (action_group,
717                                             modest_msg_edit_file_format_action_entries,
718                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
719                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
720                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
721                                             obj);
722         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
723         g_object_unref (action_group);
724
725         /* Load the UI definition */
726         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
727                                          &error);
728         if (error != NULL) {
729                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
730                 g_clear_error (&error);
731         }
732
733         /* Add accelerators */
734         gtk_window_add_accel_group (GTK_WINDOW (obj), 
735                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
736
737         parent_priv->menubar = NULL;
738
739         title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
740         value_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
741
742         /* Note: This ModestPairList* must exist for as long as the picker
743          * that uses it, because the ModestSelectorPicker uses the ID opaquely, 
744          * so it can't know how to manage its memory. */ 
745         priv->from_field    = modest_selector_picker_new (MODEST_EDITABLE_SIZE,
746                                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
747                                                           NULL, g_str_equal);
748         modest_maemo_utils_set_hbutton_layout (title_size_group, value_size_group, 
749                                                _("mail_va_from"), priv->from_field);
750
751         priv->to_field      = modest_recpt_editor_new ();
752         priv->cc_field      = modest_recpt_editor_new ();
753         priv->bcc_field     = modest_recpt_editor_new ();
754         subject_box = gtk_hbox_new (FALSE, 0);
755         priv->priority_icon = gtk_image_new ();
756         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
757         priv->subject_field = hildon_entry_new (MODEST_EDITABLE_SIZE);
758         gtk_entry_set_max_length (GTK_ENTRY (priv->subject_field) ,SUBJECT_MAX_LENGTH);
759         g_object_set (G_OBJECT (priv->subject_field), "truncate-multiline", TRUE, NULL);
760         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
761                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
762         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
763         priv->add_attachment_button = gtk_button_new ();
764         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
765         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
766         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
767         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 0.5);
768         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, HILDON_ICON_SIZE_FINGER);
769         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
770         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
771         priv->attachments_view = modest_attachments_view_new (NULL);
772         
773         priv->header_box = gtk_vbox_new (FALSE, 0);
774         
775         to_caption = modest_maemo_utils_create_captioned_with_size_type 
776                 (title_size_group, value_size_group,
777                  _("mail_va_to"), priv->to_field,
778                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
779         priv->cc_caption = modest_maemo_utils_create_captioned_with_size_type 
780                 (title_size_group, value_size_group,
781                  _("mail_va_cc"), priv->cc_field,
782                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
783         priv->bcc_caption = modest_maemo_utils_create_captioned_with_size_type
784                 (title_size_group, value_size_group,
785                  _("mail_va_hotfix1"), priv->bcc_field,
786                  HILDON_SIZE_AUTO_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
787         subject_caption = modest_maemo_utils_create_captioned (title_size_group, value_size_group,
788                                                                _("mail_va_subject"), subject_box);
789         priv->attachments_caption = modest_maemo_utils_create_captioned_with_size_type (title_size_group, value_size_group,
790                                                                                         _("mail_va_attachment"), 
791                                                                                         priv->attachments_view,
792                                                                                         HILDON_SIZE_AUTO_WIDTH |
793                                                                                         HILDON_SIZE_AUTO_HEIGHT);
794         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), value_size_group); */
795         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), value_size_group); */
796         /* modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), value_size_group); */
797         g_object_unref (title_size_group);
798         g_object_unref (value_size_group);
799
800         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->from_field, FALSE, FALSE, 0);
801         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
802         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
803         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
804         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
805         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
806         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
807
808         init_wp_text_view_style ();
809
810         priv->msg_body = wp_text_view_new ();
811         
812
813         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
814         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
815         g_object_set (priv->text_buffer, "font_scale", DEFAULT_FONT_SCALE, NULL);
816         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
817 #if (GTK_MINOR_VERSION >= 10)
818         gtk_text_buffer_register_serialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), NULL);
819         deserialize_type = gtk_text_buffer_register_deserialize_tagset(GTK_TEXT_BUFFER(priv->text_buffer), 
820                                                                        NULL);
821         gtk_text_buffer_deserialize_set_can_create_tags (GTK_TEXT_BUFFER (priv->text_buffer), 
822                                                          deserialize_type, TRUE);
823 #endif
824         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
825
826         priv->find_toolbar = hildon_find_toolbar_new (NULL);
827         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
828
829 /*      g_signal_connect (G_OBJECT (obj), "key_pressed", G_CALLBACK (on_key_pressed), NULL) */
830
831         priv->pannable = hildon_pannable_area_new ();
832         
833         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
834
835         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
836         priv->frame = gtk_frame_new (NULL);
837         gtk_box_pack_start (GTK_BOX(main_vbox), priv->frame, TRUE, TRUE, 0);
838
839         hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (priv->pannable), main_vbox);
840         gtk_widget_show_all (GTK_WIDGET(priv->pannable));
841         
842         window_box = gtk_vbox_new (FALSE, 0);
843         gtk_container_add (GTK_CONTAINER(obj), window_box);
844
845         gtk_box_pack_start (GTK_BOX (window_box), priv->pannable, TRUE, TRUE, 0);
846
847         gtk_container_add (GTK_CONTAINER (priv->frame), priv->msg_body);
848
849         /* Set window icon */
850         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON, MODEST_ICON_SIZE_BIG); 
851         if (window_icon) {
852                 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
853                 g_object_unref (window_icon);
854         }       
855 }
856         
857 static void
858 modest_msg_edit_window_disconnect_signals (ModestWindow *window)
859 {
860         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
861
862         if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
863             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
864                                            priv->clipboard_change_handler_id))
865                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), 
866                                              priv->clipboard_change_handler_id);
867         if (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD) &&
868             g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
869                                            priv->default_clipboard_change_handler_id))
870                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
871                                              priv->default_clipboard_change_handler_id);
872
873         if (priv->account_removed_handler_id && 
874             g_signal_handler_is_connected (modest_runtime_get_account_store (), 
875                                            priv->account_removed_handler_id))
876                 g_signal_handler_disconnect(modest_runtime_get_account_store (), 
877                                            priv->account_removed_handler_id);
878 }
879
880 static void
881 modest_msg_edit_window_finalize (GObject *obj)
882 {
883         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
884         
885         /* Sanity check: shouldn't be needed, the window mgr should
886            call this function before */
887         modest_msg_edit_window_disconnect_signals (MODEST_WINDOW (obj));
888
889         if (priv->font_dialog != NULL) {
890                 gtk_dialog_response (GTK_DIALOG (priv->font_dialog), GTK_RESPONSE_NONE);
891         }
892
893         if (priv->clipboard_text != NULL) {
894                 g_free (priv->clipboard_text);
895                 priv->clipboard_text = NULL;
896         }
897         
898         if (priv->draft_msg != NULL) {
899                 TnyHeader *header = tny_msg_get_header (priv->draft_msg);
900                 if (TNY_IS_HEADER (header)) {
901                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
902                         modest_window_mgr_unregister_header (mgr, header);
903                 }
904                 g_object_unref (priv->draft_msg);
905                 priv->draft_msg = NULL;
906         }
907         if (priv->outbox_msg != NULL) {
908                 TnyHeader *header = tny_msg_get_header (priv->outbox_msg);
909                 if (TNY_IS_HEADER (header)) {
910                         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
911                         modest_window_mgr_unregister_header (mgr, header);
912                 }
913                 g_object_unref (priv->outbox_msg);
914                 priv->outbox_msg = NULL;
915         }
916         if (priv->scroll_drag_timeout_id > 0) {
917                 g_source_remove (priv->scroll_drag_timeout_id);
918                 priv->scroll_drag_timeout_id = 0;
919         }
920         if (priv->clipboard_owner_idle > 0) {
921                 g_source_remove (priv->clipboard_owner_idle);
922                 priv->clipboard_owner_idle = 0;
923         }
924         if (priv->original_account_name)
925                 g_free (priv->original_account_name);
926         g_free (priv->msg_uid);
927         g_free (priv->last_search);
928         g_slist_free (priv->font_items_group);
929         g_slist_free (priv->size_items_group);
930         g_object_unref (priv->attachments);
931         g_object_unref (priv->images);
932
933         /* This had to stay alive for as long as the picker that used it: */
934         modest_pair_list_free (priv->from_field_protos);
935         
936         G_OBJECT_CLASS(parent_class)->finalize (obj);
937 }
938
939 static GdkPixbuf *
940 pixbuf_from_stream (TnyStream *stream, const gchar *mime_type, guint64 *stream_size)
941 {
942         GdkPixbufLoader *loader;
943         GdkPixbuf *pixbuf;
944         guint64 size;
945         
946         size = 0;
947
948         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
949
950         if (loader == NULL) {
951                 if (stream_size)
952                         *stream_size = 0;
953                 return NULL;
954         }
955
956         tny_stream_reset (TNY_STREAM (stream));
957         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
958                 GError *error = NULL;
959                 unsigned char read_buffer[128];
960                 gint readed;
961                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
962                 size += readed;
963                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
964                         if (error)
965                                 g_error_free (error);
966                         break;
967                 }
968         }
969
970         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
971         if (pixbuf) 
972                 g_object_ref (pixbuf);
973         gdk_pixbuf_loader_close (loader, NULL);
974         g_object_unref (loader);
975
976         if (!pixbuf)
977                 return NULL;
978
979         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
980                 GdkPixbuf *new_pixbuf;
981                 gint new_height;
982                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
983                         gdk_pixbuf_get_width (pixbuf);
984                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
985                 g_object_unref (pixbuf);
986                 pixbuf = new_pixbuf;
987         }
988
989         if (stream_size)
990                 *stream_size = size;
991
992         return pixbuf;
993 }
994
995 static void
996 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
997 {
998         ModestMsgEditWindowPrivate *priv;
999         TnyIterator *iter;
1000
1001         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1002
1003         for (iter = tny_list_create_iterator (attachments);
1004              !tny_iterator_is_done (iter);
1005              tny_iterator_next (iter)) {
1006                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1007                 const gchar *cid = tny_mime_part_get_content_id (part);
1008                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1009                 if ((cid != NULL)&&(mime_type != NULL)) {
1010                         guint64 stream_size;
1011                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1012                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1013
1014
1015                         g_object_unref (stream);
1016
1017                         if (pixbuf != NULL) {
1018                                 priv->images_count ++;
1019                                 priv->images_size += stream_size;
1020                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1021                                 g_object_unref (pixbuf);
1022                         }
1023                 }
1024                 g_object_unref (part);
1025         }
1026         g_object_unref (iter);
1027 }
1028
1029 static void
1030 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1031 {
1032         TnyMimePart *parent = NULL;
1033         const gchar *content_type = NULL;
1034         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1035
1036         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1037         
1038         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1039                 parent = g_object_ref (msg);
1040         } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1041                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1042                 TnyIterator *iter;
1043
1044                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1045                 iter = tny_list_create_iterator (parts);
1046                 while (!tny_iterator_is_done (iter)) {
1047                         TnyMimePart *part;
1048                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1049                         content_type = tny_mime_part_get_content_type (part);
1050                         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1051                                 parent = part;
1052                                 break;
1053                         } else {
1054                                 g_object_unref (part);
1055                         }
1056                         tny_iterator_next (iter);
1057                 }
1058                 g_object_unref (iter);
1059                 g_object_unref (parts);
1060         }
1061
1062         if (parent != NULL) {
1063                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1064                 TnyIterator *iter;
1065
1066                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1067                 iter = tny_list_create_iterator (parts);
1068                 while (!tny_iterator_is_done (iter)) {
1069                         TnyMimePart *part;
1070                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1071                         content_type = tny_mime_part_get_content_type (part);
1072                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1073                                 tny_list_prepend (priv->images, (GObject *) part);
1074                         } 
1075                         g_object_unref (part);
1076                         tny_iterator_next (iter);
1077                 }
1078                 g_object_unref (iter);
1079                 g_object_unref (parts);
1080                 g_object_unref (parent);
1081         }
1082 }
1083
1084 static void
1085 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1086 {
1087         TnyIterator *iter;
1088         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1089
1090         for (iter = tny_list_create_iterator (attachments) ; 
1091              !tny_iterator_is_done (iter);
1092              tny_iterator_next (iter)) {
1093                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1094                 const gchar *cid = tny_mime_part_get_content_id (part);
1095                 if (cid != NULL) {
1096                         char *invalid = NULL;
1097                         gint int_cid = strtol (cid, &invalid, 10);
1098                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1099                                 priv->next_cid = int_cid + 1;
1100                         }
1101                 }
1102                 g_object_unref (part);
1103         }
1104         g_object_unref (iter);
1105 }
1106
1107 static void
1108 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1109 {
1110         TnyHeader *header;
1111         gchar *to, *cc, *bcc, *subject;
1112         gchar *body;
1113         ModestMsgEditWindowPrivate *priv;
1114         ModestWindowPrivate *parent_priv;
1115         GtkTextIter iter;
1116         TnyHeaderFlags priority_flags;
1117         TnyFolder *msg_folder;
1118         gboolean is_html = FALSE;
1119         gboolean field_view_set;
1120         
1121         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1122         g_return_if_fail (TNY_IS_MSG (msg));
1123
1124         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1125         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1126
1127         header = tny_msg_get_header (msg);
1128         to      = tny_header_dup_to (header);
1129         cc      = tny_header_dup_cc (header);
1130         bcc     = tny_header_dup_bcc (header);
1131         subject = tny_header_dup_subject (header);
1132         priority_flags = tny_header_get_priority (header);
1133
1134         if (to)
1135                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
1136
1137         field_view_set = TRUE;
1138         if (cc) {
1139                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
1140                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1141                 gtk_widget_show (priv->cc_caption);
1142         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1143                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1144                 gtk_widget_hide (priv->cc_caption);
1145                 field_view_set = FALSE;
1146         }
1147         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1148
1149         field_view_set = TRUE;
1150         if (bcc) {
1151                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1152                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1153                 gtk_widget_show (priv->bcc_caption);
1154         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1155                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1156                 gtk_widget_hide (priv->bcc_caption);
1157                 field_view_set = FALSE;
1158         }
1159         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1160
1161
1162         if (subject)
1163                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1164         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1165                                                    priority_flags);
1166
1167         update_window_title (self);
1168
1169         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1170         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1171
1172         if ((body == NULL)||(body[0] == '\0')) {
1173                 g_free (body);
1174                 body = modest_text_utils_convert_to_html ("");
1175                 is_html = FALSE;
1176         }
1177         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1178         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1179                                             (gchar *) body,
1180                                             strlen (body));
1181         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1182         g_free (body);
1183
1184         /* Add attachments to the view */
1185         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1186         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1187         if (tny_list_get_length (priv->attachments) == 0) {
1188                 gtk_widget_hide (priv->attachments_caption);
1189         } else {
1190                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1191                 gtk_widget_show_all (priv->attachments_caption);
1192         }
1193         get_related_images (self, msg);
1194         update_next_cid (self, priv->attachments);
1195         update_next_cid (self, priv->images);
1196         replace_with_images (self, priv->images);
1197
1198         if (preserve_is_rich && !is_html) {
1199                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1200         /* Get the default format required from configuration */
1201         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1202                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1203         }
1204
1205         /* Set the default focus depending on having already a To: field or not */
1206         if ((!to)||(*to == '\0')) {
1207                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1208         } else {
1209                 gtk_widget_grab_focus (priv->msg_body);
1210         }
1211
1212         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1213
1214         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1215         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1216
1217         modest_msg_edit_window_set_modified (self, FALSE);
1218
1219         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1220         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1221         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1222         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1223
1224         if (priv->msg_uid) {
1225                 g_free (priv->msg_uid);
1226                 priv->msg_uid = NULL;
1227         }
1228
1229         /* we should set a reference to the incoming message if it is a draft */
1230         msg_folder = tny_msg_get_folder (msg);
1231         if (msg_folder) {               
1232                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1233                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1234                         if (type == TNY_FOLDER_TYPE_INVALID)
1235                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1236                         
1237                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1238                                 priv->draft_msg = g_object_ref(msg);
1239                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1240                                 priv->outbox_msg = g_object_ref(msg);
1241                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1242                 }
1243                 g_object_unref (msg_folder);
1244         }
1245
1246         g_free (to);
1247         g_free (subject);
1248         g_free (cc);
1249         g_free (bcc);
1250 }
1251
1252 static void
1253 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
1254                                 gpointer data)
1255 {
1256         GList *item_children, *node;
1257         GtkWidget *bin_child;
1258
1259         bin_child = gtk_bin_get_child (GTK_BIN(item));
1260
1261         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
1262         
1263         for (node = item_children; node != NULL; node = g_list_next (node)) {
1264                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
1265                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
1266                 }
1267         }
1268         g_list_free (item_children);
1269 }
1270
1271 static void
1272 menu_tool_button_dont_expand (GtkMenuToolButton *item)
1273 {
1274         GtkWidget *box;
1275         GList *item_children, *node;
1276
1277         box = gtk_bin_get_child (GTK_BIN (item));
1278         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
1279         item_children = gtk_container_get_children (GTK_CONTAINER (box));
1280         
1281         for (node = item_children; node != NULL; node = g_list_next (node)) {
1282                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
1283                 if (GTK_IS_TOGGLE_BUTTON (node->data))
1284                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
1285                 else if (GTK_IS_BUTTON (node->data))
1286                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
1287         }
1288         g_list_free (item_children);
1289 }
1290
1291
1292 static void
1293 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1294 {
1295         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1296         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1297         GtkWidget *placeholder;
1298         GtkWidget *tool_item;
1299         gint insert_index;
1300         gchar size_text[5];
1301         gint size_index;
1302         gint font_index;
1303         GtkWidget *sizes_menu;
1304         GtkWidget *fonts_menu;
1305         GSList *radio_group = NULL;
1306         GSList *node = NULL;
1307         gchar *markup;
1308
1309         /* Toolbar */
1310         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1311         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1312
1313         /* Font color placeholder */
1314         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1315         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1316
1317         /* font color */
1318         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1319         priv->font_color_button = hildon_color_button_new ();
1320         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
1321         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1322         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1323         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1324         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1325         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1326         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1327                                   "notify::color", 
1328                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1329                                   window);
1330
1331         /* Font size and face placeholder */
1332         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1333         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1334         /* font_size */
1335         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1336         priv->size_tool_button_label = gtk_label_new (NULL);
1337         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1338         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1339                               size_text,"</span>", NULL);
1340         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1341         g_free (markup);
1342         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1343         sizes_menu = gtk_menu_new ();
1344         priv->size_items_group = NULL;
1345         radio_group = NULL;
1346         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1347                 GtkWidget *size_menu_item;
1348
1349                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1350                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
1351                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
1352                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
1353                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
1354                 gtk_widget_show (size_menu_item);
1355
1356                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
1357                         
1358         }
1359
1360         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1361                 GtkWidget *item = (GtkWidget *) node->data;
1362                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
1363                                   window);
1364         }
1365
1366         priv->size_items_group = g_slist_reverse (priv->size_items_group);
1367         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
1368         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1369         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1370         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1371         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1372         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1373         priv->font_size_toolitem = tool_item;
1374
1375         /* font face */
1376         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
1377         priv->font_tool_button_label = gtk_label_new (NULL);
1378         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1379         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1380         g_free(markup);
1381         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1382         fonts_menu = gtk_menu_new ();
1383         priv->font_items_group = NULL;
1384         radio_group = NULL;
1385         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1386                 GtkWidget *font_menu_item;
1387                 GtkWidget *child_label;
1388
1389                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
1390                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
1391                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
1392                                       wp_get_font_name (font_index), "</span>", NULL);
1393                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
1394                 g_free (markup);
1395                 
1396                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
1397                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
1398                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
1399                 gtk_widget_show (font_menu_item);
1400
1401                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
1402                         
1403         }
1404         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
1405                 GtkWidget *item = (GtkWidget *) node->data;
1406                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
1407                                   window);
1408         }
1409         priv->font_items_group = g_slist_reverse (priv->font_items_group);
1410         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
1411         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
1412         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1413         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1414         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1415         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
1416         priv->font_face_toolitem = tool_item;
1417
1418         /* Set expand and homogeneous for remaining items */
1419         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1420         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1421         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1422         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1423         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1424         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1425         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1426         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1427         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1428
1429         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1430            will not show the tool items added to the placeholders) */
1431         gtk_widget_show_all (parent_priv->toolbar);
1432
1433         /* Set the no show all *after* showing all items. We do not
1434            want the toolbar to be shown with a show all because it
1435            could go agains the gconf setting regarding showing or not
1436            the toolbar of the editor window */
1437         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1438 }
1439
1440
1441
1442 ModestWindow*
1443 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1444 {
1445         GObject *obj;
1446         ModestWindowPrivate *parent_priv;
1447         ModestMsgEditWindowPrivate *priv;
1448         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1449         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1450         ModestWindowMgr *mgr = NULL;
1451
1452         g_return_val_if_fail (msg, NULL);
1453         g_return_val_if_fail (account_name, NULL);
1454
1455         mgr = modest_runtime_get_window_mgr ();
1456         
1457         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1458
1459         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1460         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1461
1462         /* Menubar. Update the state of some toggles */
1463         priv->from_field_protos = get_transports ();
1464         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1465         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1466         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1467                                  _("mail_va_from"));
1468         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1469                                  hildon_touch_selector_get_current_text 
1470                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1471         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1472         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1473
1474         /* Init window */
1475         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1476
1477         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1478                 
1479         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1480
1481         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1482
1483         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
1484         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1485         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1486         /* Add common dimming rules */
1487         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1488                                               modest_msg_edit_window_toolbar_dimming_entries,
1489                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1490                                               MODEST_WINDOW (obj));
1491         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1492                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1493                                                     MODEST_WINDOW (obj));
1494         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1495                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1496                                                     MODEST_WINDOW (obj));
1497         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1498                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1499                                                     MODEST_WINDOW (obj));
1500         /* Insert dimming rules group for this window */
1501         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1502         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1503
1504         /* Setup app menu */
1505         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1506
1507         /* Checks the dimming rules */
1508         g_object_unref (toolbar_rules_group);
1509         g_object_unref (clipboard_rules_group);
1510         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1511
1512         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1513
1514         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1515         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1516         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1517         priv->update_caption_visibility = TRUE;
1518
1519         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1520
1521         /* Track account-removed signal, this window should be closed
1522            in the case we're creating a mail associated to the account
1523            that is deleted */
1524         priv->account_removed_handler_id = 
1525                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1526                                   "account_removed",
1527                                   G_CALLBACK(on_account_removed),
1528                                   obj);
1529
1530         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1531
1532         return (ModestWindow*) obj;
1533 }
1534
1535 static gint
1536 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1537 {
1538         GString **string_buffer = (GString **) user_data;
1539
1540         *string_buffer = g_string_append (*string_buffer, buffer);
1541    
1542         return 0;
1543 }
1544
1545 /**
1546  * @result: A new string which should be freed with g_free().
1547  */
1548 static gchar *
1549 get_formatted_data (ModestMsgEditWindow *edit_window)
1550 {
1551         ModestMsgEditWindowPrivate *priv;
1552         GString *string_buffer = g_string_new ("");
1553         
1554         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1555
1556         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1557
1558         modest_text_utils_hyperlinkify (string_buffer);
1559
1560         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1561
1562         return g_string_free (string_buffer, FALSE);
1563                                                                         
1564 }
1565
1566 MsgData * 
1567 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1568 {
1569         MsgData *data;
1570         const gchar *account_name;
1571         ModestMsgEditWindowPrivate *priv;
1572         TnyIterator *att_iter;
1573         
1574         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1575
1576         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1577                                                                         
1578         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1579         g_return_val_if_fail (account_name, NULL);
1580         
1581         
1582         /* don't free these (except from) */
1583         data = g_slice_new0 (MsgData);
1584         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1585                                                              account_name);
1586         data->account_name = g_strdup (account_name);
1587         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1588         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1589         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1590         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1591         if (priv->draft_msg) {
1592                 data->draft_msg = g_object_ref (priv->draft_msg);
1593         } else if (priv->outbox_msg) {
1594                 data->draft_msg = g_object_ref (priv->outbox_msg);
1595         } else {
1596                 data->draft_msg = NULL;
1597         }
1598
1599         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1600         GtkTextIter b, e;
1601         gtk_text_buffer_get_bounds (buf, &b, &e);
1602         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1603
1604         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1605                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1606         else
1607                 data->html_body = NULL;
1608
1609         /* deep-copy the data */
1610         att_iter = tny_list_create_iterator (priv->attachments);
1611         data->attachments = NULL;
1612         while (!tny_iterator_is_done (att_iter)) {
1613                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1614                 if (!(TNY_IS_MIME_PART(part))) {
1615                         g_warning ("strange data in attachment list");
1616                         g_object_unref (part);
1617                         tny_iterator_next (att_iter);
1618                         continue;
1619                 }
1620                 data->attachments = g_list_append (data->attachments,
1621                                                    part);
1622                 tny_iterator_next (att_iter);
1623         }
1624         g_object_unref (att_iter);
1625
1626         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1627         att_iter = tny_list_create_iterator (priv->images);
1628         data->images = NULL;
1629         while (!tny_iterator_is_done (att_iter)) {
1630                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1631                 const gchar *cid;
1632                 if (!(TNY_IS_MIME_PART(part))) {
1633                         g_warning ("strange data in attachment list");
1634                         g_object_unref (part);
1635                         tny_iterator_next (att_iter);
1636                         continue;
1637                 }
1638                 cid = tny_mime_part_get_content_id (part);
1639                 if (cid) {                      
1640                         gchar *image_tag_id;
1641                         GtkTextTag *image_tag;
1642                         GtkTextIter iter;
1643                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1644                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1645                         g_free (image_tag_id);
1646                         
1647                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1648                         if (image_tag && 
1649                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1650                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1651                                 data->images = g_list_append (data->images,
1652                                                               g_object_ref (part));
1653                 }
1654                 g_object_unref (part);
1655                 tny_iterator_next (att_iter);
1656         }
1657         g_object_unref (att_iter);
1658         
1659         data->priority_flags = priv->priority_flags;
1660
1661         return data;
1662 }
1663
1664
1665 static void
1666 unref_gobject (GObject *obj, gpointer data)
1667 {
1668         if (!G_IS_OBJECT(obj))
1669                 return;
1670         g_object_unref (obj);
1671 }
1672
1673 void 
1674 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1675                                                       MsgData *data)
1676 {
1677         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1678
1679         if (!data)
1680                 return;
1681
1682         g_free (data->to);
1683         g_free (data->cc);
1684         g_free (data->bcc);
1685         g_free (data->from);
1686         g_free (data->subject);
1687         g_free (data->plain_body);
1688         g_free (data->html_body);
1689         g_free (data->account_name);
1690         
1691         if (data->draft_msg != NULL) {
1692                 g_object_unref (data->draft_msg);
1693                 data->draft_msg = NULL;
1694         }
1695         
1696         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1697         g_list_free (data->attachments);
1698         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1699         g_list_free (data->images);
1700         
1701         g_slice_free (MsgData, data);
1702 }
1703
1704 void                    
1705 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1706                                        gint *parts_count,
1707                                        guint64 *parts_size)
1708 {
1709         ModestMsgEditWindowPrivate *priv;
1710
1711         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1712
1713         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1714
1715         /* TODO: add images */
1716         *parts_size += priv->images_size;
1717         *parts_count += priv->images_count;
1718
1719 }
1720
1721 ModestMsgEditFormat
1722 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1723 {
1724         gboolean rich_text;
1725         ModestMsgEditWindowPrivate *priv = NULL;
1726         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1727
1728         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1729
1730         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1731         if (rich_text)
1732                 return MODEST_MSG_EDIT_FORMAT_HTML;
1733         else
1734                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1735 }
1736
1737 void
1738 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1739                                    ModestMsgEditFormat format)
1740 {
1741         ModestMsgEditWindowPrivate *priv;
1742
1743         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1744         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1745
1746         switch (format) {
1747         case MODEST_MSG_EDIT_FORMAT_HTML:
1748                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1749                 break;
1750         case MODEST_MSG_EDIT_FORMAT_TEXT:
1751                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1752                 break;
1753         default:
1754                 g_return_if_reached ();
1755         }
1756 }
1757
1758 ModestMsgEditFormatState *
1759 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1760 {
1761         ModestMsgEditFormatState *format_state = NULL;
1762         ModestMsgEditWindowPrivate *priv;
1763         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1764
1765         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1766         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1767
1768         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1769
1770         format_state = g_new0 (ModestMsgEditFormatState, 1);
1771         format_state->bold = buffer_format->bold&0x1;
1772         format_state->italics = buffer_format->italic&0x1;
1773         format_state->bullet = buffer_format->bullet&0x1;
1774         format_state->color = buffer_format->color;
1775         format_state->font_size = buffer_format->font_size;
1776         format_state->font_family = wp_get_font_name (buffer_format->font);
1777         format_state->justification = buffer_format->justification;
1778         g_free (buffer_format);
1779
1780         return format_state;
1781  
1782 }
1783
1784 void
1785 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1786                                          const ModestMsgEditFormatState *format_state)
1787 {
1788         ModestMsgEditWindowPrivate *priv;
1789         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1790         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1791         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1792         g_return_if_fail (format_state != NULL);
1793
1794         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1795         gtk_widget_grab_focus (priv->msg_body);
1796         buffer_format->bold = (format_state->bold != FALSE);
1797         buffer_format->italic = (format_state->italics != FALSE);
1798         buffer_format->color = format_state->color;
1799         buffer_format->font_size = format_state->font_size;
1800         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1801         buffer_format->justification = format_state->justification;
1802         buffer_format->bullet = format_state->bullet;
1803
1804         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1805
1806         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1807         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1808         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1809         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1810         buffer_format->cs.font = (buffer_format->font != current_format->font);
1811         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1812         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1813
1814         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1815         if (buffer_format->cs.bold) {
1816                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1817                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1818         }
1819         if (buffer_format->cs.italic) {
1820                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1821                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1822         }
1823         if (buffer_format->cs.color) {
1824                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1825                                               GINT_TO_POINTER (&(buffer_format->color)));
1826         }
1827         if (buffer_format->cs.font_size) {
1828                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1829                                               GINT_TO_POINTER (buffer_format->font_size));
1830         }
1831         if (buffer_format->cs.justification) {
1832                 switch (buffer_format->justification) {
1833                 case GTK_JUSTIFY_LEFT:
1834                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1835                                                       GINT_TO_POINTER(TRUE));
1836                         break;
1837                 case GTK_JUSTIFY_CENTER:
1838                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1839                                                       GINT_TO_POINTER(TRUE));
1840                         break;
1841                 case GTK_JUSTIFY_RIGHT:
1842                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1843                                                       GINT_TO_POINTER(TRUE));
1844                         break;
1845                 default:
1846                         break;
1847                 }
1848                         
1849         }
1850         if (buffer_format->cs.font) {
1851                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1852                                               GINT_TO_POINTER (buffer_format->font));
1853         }
1854         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1855         if (buffer_format->cs.bullet) {
1856                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1857                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1858         }
1859 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1860         
1861         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1862         
1863         g_free (buffer_format);
1864         g_free (current_format);
1865
1866         /* Check dimming rules */
1867         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1868         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1869 }
1870
1871 static void
1872 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1873 {
1874         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1875         GtkAction *action;
1876         ModestWindowPrivate *parent_priv;
1877         ModestMsgEditWindowPrivate *priv;
1878         GtkWidget *new_size_menuitem;
1879         GtkWidget *new_font_menuitem;
1880         
1881         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1882         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1883
1884         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1885                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1886                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1887                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1888         } else {
1889                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1890                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1891                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1892         }
1893
1894         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1895
1896         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1897         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1898
1899         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1900         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1901
1902 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1903 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1904
1905         action = NULL;
1906         switch (buffer_format->justification)
1907         {
1908         case GTK_JUSTIFY_LEFT:
1909                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1910                 break;
1911         case GTK_JUSTIFY_CENTER:
1912                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1913                 break;
1914         case GTK_JUSTIFY_RIGHT:
1915                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1916                 break;
1917         default:
1918                 break;
1919         }
1920         
1921         if (action != NULL)
1922                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1923         
1924         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1925                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1926                                          window);
1927         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1928         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1929                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1930                                            window);
1931
1932         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1933                                                       buffer_format->font_size))->data);
1934         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1935                 GtkWidget *label;
1936                 gchar *markup;
1937
1938                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1939                 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1940                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1941                 g_free (markup);
1942                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1943                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1944                                                  window);
1945                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1946                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1947                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1948                                                    window);
1949         }
1950
1951         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1952                                                       buffer_format->font))->data);
1953         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1954                 GtkWidget *label;
1955                 gchar *markup;
1956
1957                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1958                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1959                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1960                 g_free (markup);
1961                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1962                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1963                                                  window);
1964                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1965                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1966                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1967                                                    window);
1968         }
1969
1970         g_free (buffer_format);
1971
1972 }
1973
1974 #ifdef MODEST_HILDON_VERSION_0
1975 void
1976 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1977 {
1978         
1979         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1980         ModestMsgEditWindowPrivate *priv;
1981         GtkWidget *dialog = NULL;
1982         gint response;
1983         GdkColor *new_color = NULL;
1984
1985         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1986         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1987         
1988         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1989         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1990         g_free (buffer_format);
1991
1992         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1993                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1994                 if (new_color != NULL) {
1995                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1996                                                       (gpointer) new_color);
1997                 }
1998         }
1999         gtk_widget_destroy (dialog);
2000 }
2001
2002
2003 void
2004 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2005 {
2006         
2007         ModestMsgEditWindowPrivate *priv;
2008         GtkWidget *dialog = NULL;
2009         gint response;
2010         GdkColor *old_color = NULL;
2011         const GdkColor *new_color = NULL;
2012         
2013         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2014         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2015         
2016         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2017         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2018
2019         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2020                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2021                 if (new_color != NULL)
2022                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2023         }
2024         gtk_widget_destroy (dialog);
2025
2026 }
2027
2028 #else 
2029 void
2030 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2031 {
2032         
2033         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2034         ModestMsgEditWindowPrivate *priv;
2035         GtkWidget *dialog = NULL;
2036
2037         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2038         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2039                 
2040         dialog = hildon_color_chooser_new ();
2041         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2042         g_free (buffer_format);
2043
2044         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2045                 GdkColor col;
2046                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2047                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2048                                               (gpointer) &col);
2049         }
2050         gtk_widget_destroy (dialog);
2051 }
2052
2053
2054 void
2055 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2056 {
2057         
2058         ModestMsgEditWindowPrivate *priv;
2059         GtkWidget *dialog = NULL;
2060         GdkColor *old_color = NULL;
2061         
2062         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2063         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2064         
2065         dialog = hildon_color_chooser_new ();
2066         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2067
2068         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2069                 GdkColor col;
2070                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2071                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2072         }
2073         gtk_widget_destroy (dialog);
2074 }
2075
2076 #endif /*!MODEST_HILDON_VERSION_0*/
2077
2078
2079
2080 static TnyStream*
2081 create_stream_for_uri (const gchar* uri)
2082 {
2083         if (!uri)
2084                 return NULL;
2085                 
2086         TnyStream *result = NULL;
2087
2088         GnomeVFSHandle *handle = NULL;
2089         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2090         if (test == GNOME_VFS_OK) {
2091                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2092                 /* Streams over OBEX (Bluetooth) are not seekable but
2093                  * we expect them to be (we might need to read them
2094                  * several times). So if this is a Bluetooth URI just
2095                  * read the whole file into memory (this is not a fast
2096                  * protocol so we can assume that these files are not
2097                  * going to be very big) */
2098                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2099                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2100                         TnyStream *memstream = tny_camel_mem_stream_new ();
2101                         tny_stream_write_to_stream (vfssstream, memstream);
2102                         g_object_unref (vfssstream);
2103                         result = memstream;
2104                 } else {
2105                         result = vfssstream;
2106                 }
2107         }
2108         
2109         return result;
2110 }
2111
2112 void
2113 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2114 {
2115         
2116         ModestMsgEditWindowPrivate *priv;
2117         GtkWidget *dialog = NULL;
2118         gint response = 0;
2119         GSList *uris = NULL;
2120         GSList *uri_node = NULL;
2121         
2122         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2123         
2124         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2125         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2126         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2127
2128         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2129
2130         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2131                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2132
2133         response = gtk_dialog_run (GTK_DIALOG (dialog));
2134         switch (response) {
2135         case GTK_RESPONSE_OK:
2136                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2137                 break;
2138         default:
2139                 break;
2140         }
2141         gtk_widget_destroy (dialog);
2142
2143         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2144                 const gchar *uri;
2145                 GnomeVFSHandle *handle = NULL;
2146                 GnomeVFSResult result;
2147                 GtkTextIter position;
2148                 GtkTextMark *insert_mark;
2149
2150                 uri = (const gchar *) uri_node->data;
2151                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2152                 if (result == GNOME_VFS_OK) {
2153                         GdkPixbuf *pixbuf;
2154                         GnomeVFSFileInfo *info;
2155                         gchar *filename, *basename, *escaped_filename;
2156                         TnyMimePart *mime_part;
2157                         gchar *content_id;
2158                         const gchar *mime_type = NULL;
2159                         GnomeVFSURI *vfs_uri;
2160                         guint64 stream_size;
2161
2162                         gnome_vfs_close (handle);
2163                         vfs_uri = gnome_vfs_uri_new (uri);
2164
2165                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2166                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2167                         g_free (escaped_filename);
2168                         gnome_vfs_uri_unref (vfs_uri);
2169                         info = gnome_vfs_file_info_new ();
2170
2171                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2172                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2173                             == GNOME_VFS_OK)
2174                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2175
2176                         mime_part = tny_platform_factory_new_mime_part
2177                                 (modest_runtime_get_platform_factory ());
2178                                 
2179                         TnyStream *stream = create_stream_for_uri (uri);
2180
2181                         if (stream == NULL) {
2182
2183                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2184                                 
2185                                 g_object_unref (mime_part);
2186                                 gnome_vfs_file_info_unref (info);
2187                                 continue;
2188                         }
2189
2190                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2191                         
2192                         content_id = g_strdup_printf ("%d", priv->next_cid);
2193                         tny_mime_part_set_content_id (mime_part, content_id);
2194                         g_free (content_id);
2195                         priv->next_cid++;
2196                         
2197                         basename = g_path_get_basename (filename);
2198                         tny_mime_part_set_filename (mime_part, basename);
2199                         g_free (basename);
2200
2201                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2202                         
2203                         if (pixbuf != NULL) {
2204                                 priv->images_size += stream_size;
2205                                 priv->images_count ++;
2206                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2207                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2208                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2209                                 g_object_unref (pixbuf);
2210                         } 
2211
2212                         tny_list_prepend (priv->images, (GObject *) mime_part);
2213                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2214                         g_free (filename);
2215                         g_object_unref (mime_part);
2216                         gnome_vfs_file_info_unref (info);
2217
2218                 }
2219         }
2220
2221
2222 }
2223
2224 void
2225 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2226 {       
2227         GtkWidget *dialog = NULL;
2228         gint response = 0;
2229         GSList *uris = NULL;
2230         GSList *uri_node;
2231         GnomeVFSFileSize total_size, allowed_size;
2232         ModestMsgEditWindowPrivate *priv;
2233         gint att_num;
2234         guint64 att_size;
2235
2236         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2237                 
2238         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2239
2240         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2241                 return;
2242         
2243         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2244         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2245         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2246         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog), GTK_WINDOW (window));
2247
2248         response = gtk_dialog_run (GTK_DIALOG (dialog));
2249         switch (response) {
2250         case GTK_RESPONSE_OK:
2251                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2252                 break;
2253         default:
2254                 break;
2255         }
2256         gtk_widget_destroy (dialog);
2257
2258         /* allowed size is the maximum size - what's already there */
2259         modest_attachments_view_get_sizes (
2260                 MODEST_ATTACHMENTS_VIEW (priv->attachments_view), 
2261                 &att_num, &att_size);
2262         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2263
2264         total_size = 0;
2265         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2266
2267                 const gchar *uri = (const gchar *) uri_node->data;
2268                 
2269                 total_size += modest_msg_edit_window_attach_file_one 
2270                         (window, uri, allowed_size);
2271                 
2272                 if (total_size > allowed_size) {
2273                         g_warning ("%s: total size: %u", 
2274                                    __FUNCTION__, (unsigned int)total_size);
2275                         break;
2276                 }
2277
2278                 allowed_size -= total_size;
2279                 
2280
2281         }
2282         g_slist_foreach (uris, (GFunc) g_free, NULL);
2283         g_slist_free (uris);
2284 }
2285
2286
2287 GnomeVFSFileSize
2288 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2289                                         const gchar *uri, 
2290                                         GnomeVFSFileSize allowed_size)
2291
2292 {
2293         GnomeVFSHandle *handle = NULL;
2294         ModestMsgEditWindowPrivate *priv;
2295         GnomeVFSResult result;
2296         GnomeVFSFileSize size = 0;
2297         g_return_val_if_fail (window, 0);
2298         g_return_val_if_fail (uri, 0);
2299                 
2300         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2301         
2302         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2303         if (result == GNOME_VFS_OK) {
2304                 TnyMimePart *mime_part;
2305                 TnyStream *stream;
2306                 const gchar *mime_type = NULL;
2307                 gchar *basename;
2308                 gchar *escaped_filename;
2309                 gchar *filename;
2310                 gchar *content_id;
2311                 GnomeVFSFileInfo *info;
2312                 GnomeVFSURI *vfs_uri;
2313
2314                 gnome_vfs_close (handle);
2315                 vfs_uri = gnome_vfs_uri_new (uri);
2316                 
2317
2318                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2319                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2320                 g_free (escaped_filename);
2321                 gnome_vfs_uri_unref (vfs_uri);
2322
2323                 info = gnome_vfs_file_info_new ();
2324                 
2325                 if (gnome_vfs_get_file_info (uri, 
2326                                              info, 
2327                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2328                     == GNOME_VFS_OK)
2329                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2330                 mime_part = tny_platform_factory_new_mime_part
2331                         (modest_runtime_get_platform_factory ());
2332                 
2333                 /* try to get the attachment's size; this may fail for weird
2334                  * file systems, like obex, upnp... */
2335                 if (allowed_size != 0 &&
2336                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2337                         size = info->size;
2338                         if (size > allowed_size) {
2339                                 modest_platform_information_banner (NULL, NULL, 
2340                                                                     dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2341                                 return 0;
2342                         }
2343                 } else
2344                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2345                 
2346                 stream = create_stream_for_uri (uri);
2347                 
2348                 if (stream == NULL) {
2349
2350                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2351
2352                         g_object_unref (mime_part);
2353                         gnome_vfs_file_info_unref (info);
2354                         return 0;
2355                 }
2356
2357                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2358                 g_object_unref (stream);
2359                 
2360                 content_id = g_strdup_printf ("%d", priv->next_cid);
2361                 tny_mime_part_set_content_id (mime_part, content_id);
2362                 g_free (content_id);
2363                 priv->next_cid++;
2364                 
2365                 basename = g_path_get_basename (filename);
2366                 tny_mime_part_set_filename (mime_part, basename);
2367                 g_free (basename);
2368                 
2369                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2370                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2371                                                         mime_part,
2372                                                         info->size == 0, info->size);
2373                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2374                 gtk_widget_show_all (priv->attachments_caption);
2375                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2376                 g_free (filename);
2377                 g_object_unref (mime_part);
2378                 gnome_vfs_file_info_unref (info);
2379         }
2380
2381         return size;
2382 }
2383
2384 void
2385 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2386                                            TnyList *att_list)
2387 {
2388         ModestMsgEditWindowPrivate *priv;
2389         TnyIterator *iter;
2390
2391         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2392         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2393
2394         if (att_list == NULL) {
2395                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2396         } else {
2397                 g_object_ref (att_list);
2398         }
2399
2400         if (tny_list_get_length (att_list) == 0) {
2401                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2402         } else {
2403                 gboolean dialog_response;
2404                 gchar *message = NULL;
2405                 gchar *filename = NULL;
2406
2407                 if (tny_list_get_length (att_list) == 1) {
2408                         TnyMimePart *part;
2409                         iter = tny_list_create_iterator (att_list);
2410                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2411                         g_object_unref (iter);
2412                         if (TNY_IS_MSG (part)) {
2413                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2414                                 if (header) {
2415                                         filename = tny_header_dup_subject (header);
2416                                         g_object_unref (header);
2417                                 }
2418                                 if (filename == NULL) {
2419                                         filename = g_strdup (_("mail_va_no_subject"));
2420                                 }
2421                         } else {
2422                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2423                         }
2424                         g_object_unref (part);
2425                 } else {
2426                         filename = g_strdup ("");
2427                 }
2428                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2429                                                     tny_list_get_length (att_list)), filename);
2430                 g_free (filename);
2431
2432                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), message);
2433                 g_free (message);
2434
2435                 if (dialog_response != GTK_RESPONSE_OK) {
2436                         g_object_unref (att_list);
2437                         return;
2438                 }
2439                 hildon_banner_show_information (NULL, NULL, _("mcen_me_inbox_remove_attachments"));
2440                 
2441                 for (iter = tny_list_create_iterator (att_list);
2442                      !tny_iterator_is_done (iter);
2443                      tny_iterator_next (iter)) {
2444                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2445                         const gchar *att_id;
2446                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2447
2448                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2449                                                                    mime_part);
2450                         if (tny_list_get_length (priv->attachments) == 0)
2451                                 gtk_widget_hide (priv->attachments_caption);
2452                         att_id = tny_mime_part_get_content_id (mime_part);
2453                         if (att_id != NULL)
2454                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2455                                                                  att_id);
2456                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2457                         g_object_unref (mime_part);
2458                 }
2459                 g_object_unref (iter);
2460         }
2461
2462         g_object_unref (att_list);
2463
2464         /* if the last attachment has been removed, focus the Subject: field */
2465         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2466                 gtk_widget_grab_focus (priv->subject_field);
2467 }
2468
2469 static void
2470 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2471                                             gpointer userdata)
2472 {
2473         ModestMsgEditWindowPrivate *priv;
2474         GdkColor *new_color;
2475         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2476         
2477 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2478         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2479 #else 
2480         GdkColor col;
2481         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2482         new_color = &col;
2483 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2484
2485         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2486         
2487         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2488
2489 }
2490
2491 static void
2492 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2493                                     gpointer userdata)
2494 {
2495         ModestMsgEditWindowPrivate *priv;
2496         gint new_size_index;
2497         ModestMsgEditWindow *window;
2498         GtkWidget *label;
2499         
2500         window = MODEST_MSG_EDIT_WINDOW (userdata);
2501         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2502         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2503
2504         if (gtk_check_menu_item_get_active (menu_item)) {
2505                 gchar *markup;
2506                 WPTextBufferFormat format;
2507
2508                 memset (&format, 0, sizeof (format));
2509                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2510
2511                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2512                 
2513                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2514                 format.cs.font_size = TRUE;
2515                 format.cs.text_position = TRUE;
2516                 format.cs.font = TRUE;
2517                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2518 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2519
2520                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2521                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2522                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2523                 
2524                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2525                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2526                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2527                 g_free (markup);
2528         }
2529 }
2530
2531 static void
2532 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2533                                     gpointer userdata)
2534 {
2535         ModestMsgEditWindowPrivate *priv;
2536         gint new_font_index;
2537         ModestMsgEditWindow *window;
2538         GtkWidget *label;
2539         
2540         window = MODEST_MSG_EDIT_WINDOW (userdata);
2541         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2542         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2543
2544         if (gtk_check_menu_item_get_active (menu_item)) {
2545                 gchar *markup;
2546
2547                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2548                 
2549                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2550
2551                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2552                                                    GINT_TO_POINTER(new_font_index)))
2553                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2554                 
2555                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2556                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2557                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2558                 g_free (markup);
2559         }
2560 }
2561
2562 void
2563 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2564                                 gboolean show)
2565 {
2566         ModestMsgEditWindowPrivate *priv = NULL;
2567         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2568
2569         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2570         if (!priv->update_caption_visibility)
2571                 return;
2572
2573         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2574         if (show)
2575                 gtk_widget_show (priv->cc_caption);
2576         else
2577                 gtk_widget_hide (priv->cc_caption);
2578
2579         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2580 }
2581
2582 void
2583 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2584                                  gboolean show)
2585 {
2586         ModestMsgEditWindowPrivate *priv = NULL;
2587         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2588
2589         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2590         if (!priv->update_caption_visibility)
2591                 return;
2592
2593         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2594         if (show)
2595                 gtk_widget_show (priv->bcc_caption);
2596         else
2597                 gtk_widget_hide (priv->bcc_caption);
2598
2599         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2600 }
2601
2602 static void
2603 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2604                                          ModestRecptEditor *editor)
2605 {
2606         ModestMsgEditWindowPrivate *priv;
2607
2608         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2609         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2610         
2611         /* we check for low-mem; in that case, show a warning, and don't allow
2612          * for the addressbook
2613          */
2614         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2615                 return;
2616
2617         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2618
2619         if (editor == NULL) {
2620                 GtkWidget *view_focus;
2621                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2622
2623                 /* This code should be kept in sync with ModestRecptEditor. The
2624                    textview inside the recpt editor is the one that really gets the
2625                    focus. As it's inside a scrolled window, and this one inside the
2626                    hbox recpt editor inherits from, we'll need to go up in the 
2627                    hierarchy to know if the text view is part of the recpt editor
2628                    or if it's a different text entry */
2629
2630                 if (gtk_widget_get_parent (view_focus)) {
2631                         GtkWidget *first_parent;
2632
2633                         first_parent = gtk_widget_get_parent (view_focus);
2634                         if (gtk_widget_get_parent (first_parent) && 
2635                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2636                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2637                         }
2638                 }
2639
2640                 if (editor == NULL)
2641                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2642
2643         }
2644
2645         modest_address_book_select_addresses (editor);
2646
2647 }
2648
2649 void
2650 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2651 {
2652         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2653
2654         modest_msg_edit_window_open_addressbook (window, NULL);
2655 }
2656
2657 static void
2658 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2659                                      gboolean show_toolbar)
2660 {
2661         ModestWindowPrivate *parent_priv;
2662
2663         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2664         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2665
2666         /* We can not just use the code of
2667            modest_msg_edit_window_setup_toolbar because it has a
2668            mixture of both initialization and creation code. */
2669         if (show_toolbar)
2670                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2671         else
2672                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2673 }
2674
2675 void
2676 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2677                                            TnyHeaderFlags priority_flags)
2678 {
2679         ModestMsgEditWindowPrivate *priv;
2680         ModestWindowPrivate *parent_priv;
2681
2682         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2683
2684         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2685         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2686
2687         if (priv->priority_flags != priority_flags) {
2688                 GtkAction *priority_action = NULL;
2689
2690                 priv->priority_flags = priority_flags;
2691
2692                 switch (priority_flags) {
2693                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2694                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2695                                                       MODEST_HEADER_ICON_HIGH, 
2696                                                       HILDON_ICON_SIZE_XSMALL);
2697                         gtk_widget_show (priv->priority_icon);
2698                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2699                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2700                         break;
2701                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2702                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2703                                                       MODEST_HEADER_ICON_LOW,
2704                                                       HILDON_ICON_SIZE_XSMALL);
2705                         gtk_widget_show (priv->priority_icon);
2706                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2707                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2708                         break;
2709                 default:
2710                         gtk_widget_hide (priv->priority_icon);
2711                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2712                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2713                         break;
2714                 }
2715                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2716                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2717         }
2718 }
2719
2720 void
2721 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2722                                         gint file_format)
2723 {
2724         ModestMsgEditWindowPrivate *priv;
2725         ModestWindowPrivate *parent_priv;
2726         gint current_format;
2727
2728         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2729
2730         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2731         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2732
2733         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2734                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2735
2736         if (current_format != file_format) {
2737                 switch (file_format) {
2738                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2739                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2740                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2741                         break;
2742                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2743                 {
2744                         GtkWidget *dialog;
2745                         gint response;
2746                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2747                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2748                         gtk_widget_destroy (dialog);
2749                         if (response == GTK_RESPONSE_OK) {
2750                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2751                         } else {
2752                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2753                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2754                         }
2755                 }
2756                         break;
2757                 }
2758                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2759                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2760                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2761         }
2762 }
2763
2764 void
2765 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2766 {
2767         GtkWidget *dialog;
2768         ModestMsgEditWindowPrivate *priv;
2769         WPTextBufferFormat oldfmt, fmt;
2770         gint old_position = 0;
2771         gint response = 0;
2772         gint position = 0;
2773         gint font_size;
2774         GdkColor *color = NULL;
2775         gboolean bold, bold_set, italic, italic_set;
2776         gboolean underline, underline_set;
2777         gboolean strikethrough, strikethrough_set;
2778         gboolean position_set;
2779         gboolean font_size_set, font_set, color_set;
2780         gchar *font_name;
2781
2782         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2783         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2784         
2785         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2786         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2787                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2788
2789         /* First we get the currently selected font information */
2790         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2791
2792         switch (oldfmt.text_position) {
2793         case TEXT_POSITION_NORMAL:
2794                 old_position = 0;
2795                 break;
2796         case TEXT_POSITION_SUPERSCRIPT:
2797                 old_position = 1;
2798                 break;
2799         default:
2800                 old_position = -1;
2801                 break;
2802         }
2803
2804         g_object_set (G_OBJECT (dialog),
2805                       "bold", oldfmt.bold != FALSE,
2806                       "bold-set", !oldfmt.cs.bold,
2807                       "underline", oldfmt.underline != FALSE,
2808                       "underline-set", !oldfmt.cs.underline,
2809                       "italic", oldfmt.italic != FALSE,
2810                       "italic-set", !oldfmt.cs.italic,
2811                       "strikethrough", oldfmt.strikethrough != FALSE,
2812                       "strikethrough-set", !oldfmt.cs.strikethrough,
2813                       "color", &oldfmt.color,
2814                       "color-set", !oldfmt.cs.color,
2815                       "size", wp_font_size[oldfmt.font_size],
2816                       "size-set", !oldfmt.cs.font_size,
2817                       "position", old_position,
2818                       "position-set", !oldfmt.cs.text_position,
2819                       "family", wp_get_font_name (oldfmt.font),
2820                       "family-set", !oldfmt.cs.font,
2821                       NULL);
2822
2823         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2824                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2825         gtk_widget_show_all (dialog);
2826         priv->font_dialog = dialog;
2827         response = gtk_dialog_run (GTK_DIALOG (dialog));
2828         priv->font_dialog = NULL;
2829         if (response == GTK_RESPONSE_OK) {
2830
2831                 g_object_get( dialog,
2832                               "bold", &bold,
2833                               "bold-set", &bold_set,
2834                               "underline", &underline,
2835                               "underline-set", &underline_set,
2836                               "italic", &italic,
2837                               "italic-set", &italic_set,
2838                               "strikethrough", &strikethrough,
2839                               "strikethrough-set", &strikethrough_set,
2840                               "color", &color,
2841                               "color-set", &color_set,
2842                               "size", &font_size,
2843                               "size-set", &font_size_set,
2844                               "family", &font_name,
2845                               "family-set", &font_set,
2846                               "position", &position,
2847                               "position-set", &position_set,
2848                               NULL );
2849                 
2850         }       
2851
2852         if (response == GTK_RESPONSE_OK) {
2853                 memset(&fmt, 0, sizeof(fmt));
2854                 if (bold_set) {
2855                         fmt.bold = bold;
2856                         fmt.cs.bold = TRUE;
2857                 }
2858                 if (italic_set) {
2859                         fmt.italic = italic;
2860                         fmt.cs.italic = TRUE;
2861                 }
2862                 if (underline_set) {
2863                         fmt.underline = underline;
2864                         fmt.cs.underline = TRUE;
2865                 }
2866                 if (strikethrough_set) {
2867                         fmt.strikethrough = strikethrough;
2868                         fmt.cs.strikethrough = TRUE;
2869                 }
2870                 if (position_set) {
2871                         fmt.text_position =
2872                                 ( position == 0 )
2873                                 ? TEXT_POSITION_NORMAL
2874                                 : ( ( position == 1 )
2875                                     ? TEXT_POSITION_SUPERSCRIPT
2876                                     : TEXT_POSITION_SUBSCRIPT );
2877                         fmt.cs.text_position = TRUE;
2878                         fmt.font_size = oldfmt.font_size;
2879                 }
2880                 if (color_set) {
2881                         fmt.color = *color;
2882                         fmt.cs.color = TRUE;
2883                 }
2884                 if (font_set) {
2885                         fmt.font = wp_get_font_index(font_name,
2886                                                      DEFAULT_FONT);
2887                         fmt.cs.font = TRUE;
2888                 }
2889                 g_free(font_name);
2890                 if (font_size_set) {
2891                         fmt.cs.font_size = TRUE;
2892                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2893                 }
2894                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2895                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2896         }
2897         gtk_widget_destroy (dialog);
2898         
2899         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2900 }
2901
2902 void
2903 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2904 {
2905         ModestMsgEditWindowPrivate *priv;
2906
2907         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2908         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2909         
2910         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2911
2912         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2913         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2914 }
2915
2916 void
2917 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2918 {
2919         ModestMsgEditWindowPrivate *priv;
2920
2921         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2922         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2923         
2924         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2925
2926         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2927         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2928
2929 }
2930
2931 static void  
2932 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2933 {
2934         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2935
2936         priv->can_undo = can_undo;
2937 }
2938
2939 static void  
2940 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2941 {
2942         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2943
2944         priv->can_redo = can_redo;
2945 }
2946
2947 gboolean            
2948 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2949 {
2950         ModestMsgEditWindowPrivate *priv;
2951         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2952         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2953
2954         return priv->can_undo;
2955 }
2956
2957 gboolean            
2958 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2959 {
2960         ModestMsgEditWindowPrivate *priv;
2961         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2962         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2963
2964         return priv->can_redo;
2965 }
2966
2967
2968 static void
2969 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2970 {
2971         GtkTextIter iter;
2972         GtkTextIter match_start, match_end;
2973
2974         if (image_id == NULL)
2975                 return;
2976
2977         gtk_text_buffer_get_start_iter (buffer, &iter);
2978
2979         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2980                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2981                 GSList *node;
2982                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2983                         GtkTextTag *tag = (GtkTextTag *) node->data;
2984                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2985                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2986                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2987                                         gint offset;
2988                                         offset = gtk_text_iter_get_offset (&match_start);
2989                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2990                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2991                                 }
2992                         }
2993                 }
2994                 gtk_text_iter_forward_char (&iter);
2995         }
2996 }
2997
2998 gboolean
2999 message_is_empty (ModestMsgEditWindow *window)
3000 {
3001         ModestMsgEditWindowPrivate *priv = NULL;
3002
3003         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3004         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3005
3006         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3007          * so we can ignore markup.
3008          */
3009         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3010         gint count = 0;
3011         if (buf)
3012                 count = gtk_text_buffer_get_char_count (buf);
3013
3014         return count == 0;
3015 }
3016
3017 static gboolean
3018 msg_body_focus (GtkWidget *focus,
3019                 GdkEventFocus *event,
3020                 gpointer userdata)
3021 {
3022         
3023         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3024         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3025         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3026         return FALSE;
3027 }
3028
3029 static void
3030 recpt_field_changed (GtkTextBuffer *buffer,
3031                   ModestMsgEditWindow *editor)
3032 {
3033         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3034         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3035 }
3036
3037 static void
3038 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3039 {
3040         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3041         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3042 }
3043
3044 void
3045 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3046                                      gboolean modified)
3047 {
3048         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3049         GtkTextBuffer *buffer;
3050
3051         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3052         gtk_text_buffer_set_modified (buffer, modified);
3053         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3054         gtk_text_buffer_set_modified (buffer, modified);
3055         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3056         gtk_text_buffer_set_modified (buffer, modified);
3057         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3058 }
3059
3060 gboolean
3061 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3062 {
3063         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3064         const char *account_name;
3065         GtkTextBuffer *buffer;
3066
3067         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3068         if (gtk_text_buffer_get_modified (buffer))
3069                 return TRUE;
3070         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3071         if (gtk_text_buffer_get_modified (buffer))
3072                 return TRUE;
3073         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3074         if (gtk_text_buffer_get_modified (buffer))
3075                 return TRUE;
3076         if (gtk_text_buffer_get_modified (priv->text_buffer))
3077                 return TRUE;
3078         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3079         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3080                 return TRUE;
3081         }
3082
3083         return FALSE;
3084 }
3085
3086
3087
3088
3089 gboolean
3090 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3091 {
3092         ModestMsgEditWindowPrivate *priv = NULL;
3093         
3094         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3095         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3096
3097         /* check if there's no recipient added */
3098         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3099             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3100             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3101                 /* no recipient contents, then select contacts */
3102                 modest_msg_edit_window_open_addressbook (window, NULL);
3103                 return FALSE;
3104         }
3105
3106         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3107                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3108                 return FALSE;
3109         }
3110         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3111                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3112                 return FALSE;
3113         }
3114         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3115                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3116                 return FALSE;
3117         }
3118
3119         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3120             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3121                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3122
3123         return TRUE;
3124
3125 }
3126
3127 static void
3128 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3129                                                ModestMsgEditWindow *window)
3130 {
3131         modest_msg_edit_window_offer_attach_file (window);
3132 }
3133
3134 const gchar *
3135 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3136 {
3137         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3138
3139         return priv->clipboard_text;
3140 }
3141
3142 static void
3143 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3144                                                GdkEvent *event,
3145                                                ModestMsgEditWindow *window)
3146 {
3147         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3148         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3149         gchar *text = NULL;
3150         if (!GTK_WIDGET_VISIBLE (window))
3151                 return;
3152
3153         g_object_ref (window);
3154         text = gtk_clipboard_wait_for_text (selection_clipboard);
3155
3156         if (priv->clipboard_text != NULL) {
3157                 g_free (priv->clipboard_text);
3158         }
3159         priv->clipboard_text = text;
3160
3161         if (GTK_WIDGET_VISIBLE (window)) {
3162                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3163         }
3164         g_object_unref (window);
3165 }
3166
3167 static gboolean clipboard_owner_change_idle (gpointer userdata)
3168 {
3169         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3170         ModestMsgEditWindowPrivate *priv;
3171
3172         gdk_threads_enter ();
3173         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3174         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3175
3176         priv->clipboard_owner_idle = 0;
3177         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3178         gdk_threads_leave ();
3179
3180         return FALSE;
3181 }
3182
3183 static void
3184 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3185 {
3186         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3187         if (priv->clipboard_owner_idle == 0) {
3188                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3189         }
3190 }
3191
3192 static void 
3193 subject_field_move_cursor (GtkEntry *entry,
3194                            GtkMovementStep step,
3195                            gint a1,
3196                            gboolean a2,
3197                            gpointer window)
3198 {
3199         if (!GTK_WIDGET_VISIBLE (window))
3200                 return;
3201
3202         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3203 }
3204
3205 static void 
3206 update_window_title (ModestMsgEditWindow *window)
3207 {
3208         ModestMsgEditWindowPrivate *priv = NULL;
3209         const gchar *subject;
3210
3211         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3212         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3213         if (subject == NULL || subject[0] == '\0')
3214                 subject = _("mail_va_new_email");
3215
3216         gtk_window_set_title (GTK_WINDOW (window), subject);
3217
3218 }
3219
3220 static void  
3221 subject_field_changed (GtkEditable *editable, 
3222                        ModestMsgEditWindow *window)
3223 {
3224         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3225         update_window_title (window);
3226         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3227         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3228         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3229 }
3230
3231 static void  
3232 subject_field_insert_text (GtkEditable *editable, 
3233                            gchar *new_text,
3234                            gint new_text_length,
3235                            gint *position,
3236                            ModestMsgEditWindow *window)
3237 {
3238         GString *result = g_string_new ("");
3239         gchar *current;
3240         gint result_len = 0;
3241         const gchar *entry_text = NULL;
3242         gint old_length;
3243
3244         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3245         old_length = g_utf8_strlen (entry_text, -1);
3246
3247         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3248                 gunichar c = g_utf8_get_char_validated (current, 8);
3249                 /* Invalid unichar, stop */
3250                 if (c == -1)
3251                         break;
3252                 /* a bullet */
3253                 if (c == 0x2022)
3254                         continue;
3255                 result = g_string_append_unichar (result, c);
3256                 result_len++;
3257         }
3258
3259         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3260                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3261                 if (result_len > 0)
3262                 {
3263                         /* Prevent endless recursion */
3264                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3265                         g_signal_emit_by_name (editable, "insert-text", 
3266                                                (gpointer) result->str, (gpointer) result->len,
3267                                                (gpointer) position, (gpointer) window);
3268                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3269                 }
3270         }
3271
3272         if (result_len + old_length > 1000) {
3273                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3274                                                 dgettext("hildon-common-strings",
3275                                                          "ckdg_ib_maximum_characters_reached"));
3276         }
3277         
3278         g_string_free (result, TRUE);
3279 }
3280
3281 void
3282 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3283                                             gboolean show)
3284 {
3285         ModestMsgEditWindowPrivate *priv = NULL;
3286
3287         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3288         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3289
3290         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3291
3292         if (show) {
3293                 gtk_widget_show_all (priv->find_toolbar);
3294                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3295         } else {
3296                 gtk_widget_hide_all (priv->find_toolbar);
3297                 gtk_widget_grab_focus (priv->msg_body);
3298         }
3299     
3300 }
3301
3302 static gboolean 
3303 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3304                                           const gchar *str,
3305                                           GtkTextIter *match_start,
3306                                           GtkTextIter *match_end)
3307 {
3308         GtkTextIter end_iter;
3309         gchar *str_casefold;
3310         gint str_chars_n;
3311         gchar *range_text;
3312         gchar *range_casefold;
3313         gint offset;
3314         gint range_chars_n;
3315         gboolean result = FALSE;
3316
3317         if (str == NULL)
3318                 return TRUE;
3319         
3320         /* get end iter */
3321         end_iter = *iter;
3322         gtk_text_iter_forward_to_end (&end_iter);
3323
3324         str_casefold = g_utf8_casefold (str, -1);
3325         str_chars_n = strlen (str);
3326
3327         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3328         range_casefold = g_utf8_casefold (range_text, -1);
3329         range_chars_n = strlen (range_casefold);
3330
3331         if (range_chars_n < str_chars_n) {
3332                 g_free (str_casefold);
3333                 g_free (range_text);
3334                 g_free (range_casefold);
3335                 return FALSE;
3336         }
3337
3338         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3339                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3340                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3341                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3342                         result = TRUE;
3343                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3344                                                       match_start, match_end, NULL);
3345                         g_free (found_text);
3346                 }
3347                 g_free (range_subtext);
3348                 if (result)
3349                         break;
3350         }
3351         g_free (str_casefold);
3352         g_free (range_text);
3353         g_free (range_casefold);
3354
3355         return result;
3356 }
3357
3358
3359 static void 
3360 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3361                                             ModestMsgEditWindow *window)
3362 {
3363         gchar *current_search = NULL;
3364         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3365         gboolean result;
3366         GtkTextIter selection_start, selection_end;
3367         GtkTextIter match_start, match_end;
3368         gboolean continue_search = FALSE;
3369
3370         if (message_is_empty (window)) {
3371                 g_free (priv->last_search);
3372                 priv->last_search = NULL;
3373                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3374                 return;
3375         }
3376
3377         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3378         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3379                 g_free (current_search);
3380                 g_free (priv->last_search);
3381                 priv->last_search = NULL;
3382                 /* Information banner about empty search */
3383                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3384                 return;
3385         }
3386
3387         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3388                 continue_search = TRUE;
3389         } else {
3390                 g_free (priv->last_search);
3391                 priv->last_search = g_strdup (current_search);
3392         }
3393
3394         if (continue_search) {
3395                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3396                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3397                                                                    &match_start, &match_end);
3398                 if (!result)
3399                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3400         } else {
3401                 GtkTextIter buffer_start;
3402                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3403                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3404                                                                    &match_start, &match_end);
3405                 if (!result)
3406                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3407         }
3408
3409         /* Mark as selected the string found in search */
3410         if (result) {
3411                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3412                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3413                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3414         } else {
3415                 g_free (priv->last_search);
3416                 priv->last_search = NULL;
3417         }
3418         g_free (current_search);
3419 }
3420
3421 static void
3422 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3423                                            ModestMsgEditWindow *window)
3424 {
3425         ModestMsgEditWindowPrivate *priv;
3426
3427         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3428
3429         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->find_toolbar_button), FALSE);
3430 }
3431
3432 gboolean 
3433 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3434 {
3435         ModestMsgEditWindowPrivate *priv;
3436
3437         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3438         return priv->sent;
3439 }
3440
3441 void 
3442 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3443                                  gboolean sent)
3444 {
3445         ModestMsgEditWindowPrivate *priv;
3446
3447         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3448         priv->sent = sent;
3449 }
3450
3451
3452 void            
3453 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3454                                   TnyMsg *draft)
3455 {
3456         ModestMsgEditWindowPrivate *priv;
3457         TnyHeader *header = NULL;
3458
3459         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3460         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3461
3462         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3463         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3464
3465         if (priv->draft_msg != NULL) {
3466                 g_object_unref (priv->draft_msg);
3467         }
3468
3469         if (draft != NULL) {
3470                 g_object_ref (draft);
3471                 header = tny_msg_get_header (draft);
3472                 if (priv->msg_uid) {
3473                         g_free (priv->msg_uid);
3474                         priv->msg_uid = NULL;
3475                 }
3476                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3477                 if (GTK_WIDGET_REALIZED (window)) {
3478                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3479                                 gtk_widget_destroy (GTK_WIDGET (window));
3480                                 return;
3481                         }
3482                 }
3483         }
3484
3485         priv->draft_msg = draft;
3486 }
3487
3488 static void  
3489 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3490                        GtkTextIter *start, GtkTextIter *end,
3491                        gpointer userdata)
3492 {
3493         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3494         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3495         gchar *tag_name;
3496
3497         if (tag == NULL) return;
3498         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3499         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3500                 replace_with_images (window, priv->images);
3501         }
3502 }
3503
3504 void                    
3505 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3506                                  TnyMimePart *part)
3507 {
3508         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3509
3510         g_return_if_fail (TNY_IS_MIME_PART (part));
3511         tny_list_prepend (priv->attachments, (GObject *) part);
3512         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3513         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3514         gtk_widget_show_all (priv->attachments_caption);
3515         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3516 }
3517
3518 const gchar*    
3519 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3520 {
3521         ModestMsgEditWindowPrivate *priv;
3522
3523         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3524         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3525
3526         return priv->msg_uid;
3527 }
3528
3529 GtkWidget *
3530 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3531                                          ModestMsgEditWindowWidgetType widget_type)
3532 {
3533         ModestMsgEditWindowPrivate *priv;
3534
3535         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3536         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3537
3538         switch (widget_type) {
3539         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3540                 return priv->msg_body;
3541                 break;
3542         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3543                 return priv->to_field;
3544                 break;
3545         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3546                 return priv->cc_field;
3547                 break;
3548         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3549                 return priv->bcc_field;
3550                 break;
3551         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3552                 return priv->subject_field;
3553                 break;
3554         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3555                 return priv->attachments_view;
3556                 break;
3557         default:
3558                 return NULL;
3559         }
3560 }
3561
3562 static void 
3563 remove_tags (WPTextBuffer *buffer)
3564 {
3565         GtkTextIter start, end;
3566
3567         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3568         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3569
3570         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3571 }
3572
3573 static void
3574 on_account_removed (TnyAccountStore *account_store, 
3575                     TnyAccount *account,
3576                     gpointer user_data)
3577 {
3578         /* Do nothing if it's a store account, because we use the
3579            transport to send the messages */
3580         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3581                 const gchar *parent_acc = NULL;
3582                 const gchar *our_acc = NULL;
3583
3584                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3585                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3586                 /* Close this window if I'm showing a message of the removed account */
3587                 if (strcmp (parent_acc, our_acc) == 0)
3588                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3589         }
3590 }
3591
3592 typedef struct _MessageSettingsHelper {
3593         ModestMsgEditWindow *window;
3594         GSList *priority_group;
3595         GtkWidget *align_picker;
3596 } MessageSettingsHelper;
3597
3598 static void
3599 on_priority_toggle (HildonCheckButton *button, 
3600                     MessageSettingsHelper *helper)
3601 {
3602         GSList *node;
3603         ModestMsgEditWindowPrivate *priv;
3604
3605         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3606         if (hildon_check_button_get_active (button)) {
3607
3608                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3609                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3610                         if ((node_button != button) &&
3611                             hildon_check_button_get_active (node_button)) {
3612                                 hildon_check_button_set_active (node_button, FALSE);
3613                         }
3614                         if (priv->priority_flags != (TnyHeaderFlags) g_object_get_data (G_OBJECT (button), "priority"))
3615                                 modest_msg_edit_window_set_priority_flags (helper->window,
3616                                                                            (TnyHeaderFlags) 
3617                                                                            g_object_get_data (G_OBJECT (button), 
3618                                                                                               "priority"));
3619                 }
3620
3621                 
3622         } else {
3623                 gboolean found = FALSE;
3624                 /* If no one is active, activate it again */
3625                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3626                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3627                         if (hildon_check_button_get_active (node_button)) {
3628                                 found = TRUE;
3629                                 break;
3630                         }
3631                 }
3632                 if (!found) {
3633                         hildon_check_button_set_active (button, TRUE);
3634                 }
3635         }
3636 }
3637
3638 static void
3639 on_format_picker_value_changed (HildonPickerButton *button,
3640                                 MessageSettingsHelper *helper)
3641 {
3642         ModestMsgEditFormat new_format, old_format;
3643         gint file_format;
3644
3645         switch (hildon_picker_button_get_active (button)) {
3646         case 1:
3647                 new_format = MODEST_MSG_EDIT_FORMAT_HTML;
3648                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
3649                 break;
3650         case 0:
3651         default:
3652                 new_format = MODEST_MSG_EDIT_FORMAT_TEXT;
3653                 file_format = MODEST_FILE_FORMAT_PLAIN_TEXT;
3654                 break;
3655         }
3656
3657         old_format = modest_msg_edit_window_get_format (helper->window);
3658         if (new_format != old_format) {
3659                 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (helper->window), file_format);
3660
3661                 switch (modest_msg_edit_window_get_format (helper->window)) {
3662                 case MODEST_MSG_EDIT_FORMAT_TEXT:
3663                         hildon_picker_button_set_active (button, 0);
3664                         gtk_widget_set_sensitive (helper->align_picker, FALSE);
3665                         break;
3666                 case MODEST_MSG_EDIT_FORMAT_HTML:
3667                 default:
3668                         hildon_picker_button_set_active (button, 1);
3669                         gtk_widget_set_sensitive (helper->align_picker, TRUE);
3670                         break;
3671                 }
3672         }
3673 }
3674
3675 static void
3676 on_align_picker_value_changed (HildonPickerButton *button,
3677                                 MessageSettingsHelper *helper)
3678 {
3679         GtkJustification new_justify;
3680         ModestMsgEditFormatState *format_state = NULL;
3681
3682         switch (hildon_picker_button_get_active (button)) {
3683         case 1:
3684                 new_justify = GTK_JUSTIFY_CENTER;
3685                 break;
3686         case 2:
3687                 new_justify = GTK_JUSTIFY_RIGHT;
3688                 break;
3689         case 0:
3690         default:
3691                 new_justify = GTK_JUSTIFY_LEFT;
3692                 break;
3693         }
3694
3695         format_state = modest_msg_edit_window_get_format_state (helper->window);
3696         if (format_state->justification != new_justify)
3697                 format_state->justification = new_justify;
3698         modest_msg_edit_window_set_format_state (helper->window, format_state);
3699         g_free (format_state);
3700 }
3701
3702 static void
3703 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3704 {
3705         GtkWidget *dialog;
3706         GtkWidget *vbox;
3707         GtkWidget *priority_hbox;
3708         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3709         GtkWidget *captioned;
3710         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3711         GtkWidget *format_picker;
3712         GtkWidget *format_selector;
3713         GtkWidget *align_selector;
3714         ModestMsgEditWindowPrivate *priv;
3715         MessageSettingsHelper helper = {0,};
3716         ModestMsgEditFormatState *format_state = NULL;
3717
3718         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3719         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3720         helper.window = window;
3721         helper.priority_group = NULL;
3722
3723         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3724         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3725
3726         dialog = gtk_dialog_new ();
3727         vbox = gtk_vbox_new (FALSE, 0);
3728         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
3729         gtk_widget_show (vbox);
3730
3731         /* Priority toggles */
3732         priority_hbox = gtk_hbox_new (TRUE, 0);
3733         high_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3734         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3735         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3736         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3737         medium_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3738         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3739         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3740         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3741         low_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3742         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3743         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3744         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3745         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, FALSE, FALSE, 0);
3746         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, FALSE, FALSE, 0);
3747         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, FALSE, FALSE, 0);
3748         gtk_widget_show_all (priority_hbox);
3749         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3750                                                          _("mcen_me_editor_message_priority"), priority_hbox);
3751         gtk_widget_show (captioned);
3752         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3753
3754         /* format selector */
3755         format_selector = hildon_touch_selector_new_text ();
3756         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_plain_text"));
3757         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_formatted_text"));
3758         format_picker = hildon_picker_button_new (MODEST_EDITABLE_SIZE,
3759                                                   HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
3760         hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (format_picker), HILDON_TOUCH_SELECTOR (format_selector));
3761         modest_maemo_utils_set_hbutton_layout (title_sizegroup, value_sizegroup, 
3762                                                _("mcen_me_editor_format"), format_picker);
3763         gtk_widget_show_all (format_picker);
3764         gtk_box_pack_start (GTK_BOX (vbox), format_picker, FALSE, FALSE, 0);
3765         
3766         /* alignment selector */
3767         align_selector = hildon_touch_selector_new_text ();
3768         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (align_selector), _("mcen_me_editor_align_left"));
3769         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (align_selector), _("mcen_me_editor_align_centred"));
3770         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (align_selector), _("mcen_me_editor_align_right"));
3771         helper.align_picker = hildon_picker_button_new (MODEST_EDITABLE_SIZE,
3772                                                  HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
3773         hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (helper.align_picker), HILDON_TOUCH_SELECTOR (align_selector));
3774         modest_maemo_utils_set_hbutton_layout (title_sizegroup, value_sizegroup, 
3775                                                _("mcen_me_editor_align"), helper.align_picker);
3776         gtk_widget_show_all (helper.align_picker);
3777         gtk_box_pack_start (GTK_BOX (vbox), helper.align_picker, FALSE, FALSE, 0);
3778         
3779         g_object_unref (title_sizegroup);
3780         g_object_unref (value_sizegroup);
3781         gtk_window_set_title (GTK_WINDOW (dialog), _("TODO: Message settings"));
3782         
3783         /* Set current values */
3784         switch (priv->priority_flags) {
3785         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3786                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (high_toggle), TRUE);
3787                 break;
3788         case TNY_HEADER_FLAG_LOW_PRIORITY:
3789                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (low_toggle), TRUE);
3790                 break;
3791         default:
3792                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (medium_toggle), TRUE);
3793                 break;
3794         }
3795
3796         switch (modest_msg_edit_window_get_format (window)) {
3797         case MODEST_MSG_EDIT_FORMAT_TEXT:
3798                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 0);
3799                 gtk_widget_set_sensitive (helper.align_picker, FALSE);
3800                 break;
3801         case MODEST_MSG_EDIT_FORMAT_HTML:
3802         default:
3803                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 1);
3804                 gtk_widget_set_sensitive (helper.align_picker, TRUE);
3805                 break;
3806         }
3807
3808         format_state = modest_msg_edit_window_get_format_state (window);
3809         switch (format_state->justification) {
3810         case GTK_JUSTIFY_RIGHT:
3811                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 2);
3812                 break;
3813         case GTK_JUSTIFY_CENTER:
3814                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 1);
3815                 break;
3816         default:
3817                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 0);
3818                 break;
3819         
3820         }
3821         g_free (format_state);
3822
3823         /* Signal connects */
3824         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3825         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3826         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3827         g_signal_connect (G_OBJECT (format_picker), "value-changed", G_CALLBACK (on_format_picker_value_changed), &helper);
3828         g_signal_connect (G_OBJECT (helper.align_picker), "value-changed", 
3829                           G_CALLBACK (on_align_picker_value_changed), &helper);
3830         
3831         gtk_dialog_run (GTK_DIALOG (dialog));
3832         
3833         /* Read new values */
3834         
3835         gtk_widget_destroy (dialog);
3836         g_slist_free (helper.priority_group);
3837         
3838 }
3839
3840 static void on_message_settings (GtkAction *action,
3841                                  ModestMsgEditWindow *window)
3842 {
3843         modest_msg_edit_window_show_msg_settings_dialog (window);
3844 }
3845
3846 static void
3847 on_cc_button_toggled (HildonCheckButton *button,
3848                       ModestMsgEditWindow *window)
3849 {
3850         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3851
3852         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3853                                         hildon_check_button_get_active (button));
3854 }
3855
3856 static void
3857 on_bcc_button_toggled (HildonCheckButton *button,
3858                       ModestMsgEditWindow *window)
3859 {
3860         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3861
3862         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3863                                         hildon_check_button_get_active (button));
3864 }
3865
3866 static void
3867 on_find_toolbar_button_toggled (HildonCheckButton *button,
3868                                 ModestMsgEditWindow *window)
3869 {
3870         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3871         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window),
3872                                                     hildon_check_button_get_active (button));
3873
3874 }
3875
3876 static void 
3877 setup_menu (ModestMsgEditWindow *self)
3878 {
3879         ModestMsgEditWindowPrivate *priv = NULL;
3880
3881         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3882
3883         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3884
3885         /* Settings menu buttons */
3886         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"),
3887                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3888                                            NULL);
3889         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"),
3890                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3891                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3892
3893         priv->cc_button = hildon_check_button_new (0);
3894         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3895         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3896                                         FALSE);
3897         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3898                                                   NULL);
3899         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3900                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3901         priv->bcc_button = hildon_check_button_new (0);
3902         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3903         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3904                                         FALSE);
3905         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3906                                                   NULL);
3907         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3908                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3909
3910         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"),
3911                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3912                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3913         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"),
3914                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3915                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3916         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("TODO: Message settings..."),
3917                                            APP_MENU_CALLBACK (on_message_settings),
3918                                            NULL);
3919         priv->find_toolbar_button = hildon_check_button_new (0);
3920         gtk_button_set_label (GTK_BUTTON (priv->find_toolbar_button), _("mcen_me_viewer_find"));
3921         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->find_toolbar_button),
3922                                         FALSE);
3923         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->find_toolbar_button),
3924                                                   NULL);
3925         g_signal_connect (G_OBJECT (priv->find_toolbar_button), "toggled",
3926                           G_CALLBACK (on_find_toolbar_button_toggled), (gpointer) self);
3927 }
3928