* Fixes NB#97664, remove alignment option from message settings
[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_("mcen_me_message_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 (priv->font_color_toolitem, 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         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1484         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1485         /* Add common dimming rules */
1486         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1487                                               modest_msg_edit_window_toolbar_dimming_entries,
1488                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1489                                               MODEST_WINDOW (obj));
1490         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1491                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1492                                                     MODEST_WINDOW (obj));
1493         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1494                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1495                                                     MODEST_WINDOW (obj));
1496         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1497                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1498                                                     MODEST_WINDOW (obj));
1499         /* Insert dimming rules group for this window */
1500         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1501         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1502
1503         /* Setup app menu */
1504         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1505
1506         /* Checks the dimming rules */
1507         g_object_unref (toolbar_rules_group);
1508         g_object_unref (clipboard_rules_group);
1509         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1510
1511         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1512
1513         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1514         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1515         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1516         priv->update_caption_visibility = TRUE;
1517
1518         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1519
1520         /* Track account-removed signal, this window should be closed
1521            in the case we're creating a mail associated to the account
1522            that is deleted */
1523         priv->account_removed_handler_id = 
1524                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1525                                   "account_removed",
1526                                   G_CALLBACK(on_account_removed),
1527                                   obj);
1528
1529         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1530
1531         return (ModestWindow*) obj;
1532 }
1533
1534 static gint
1535 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1536 {
1537         GString **string_buffer = (GString **) user_data;
1538
1539         *string_buffer = g_string_append (*string_buffer, buffer);
1540    
1541         return 0;
1542 }
1543
1544 /**
1545  * @result: A new string which should be freed with g_free().
1546  */
1547 static gchar *
1548 get_formatted_data (ModestMsgEditWindow *edit_window)
1549 {
1550         ModestMsgEditWindowPrivate *priv;
1551         GString *string_buffer = g_string_new ("");
1552         
1553         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1554
1555         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1556
1557         modest_text_utils_hyperlinkify (string_buffer);
1558
1559         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1560
1561         return g_string_free (string_buffer, FALSE);
1562                                                                         
1563 }
1564
1565 MsgData * 
1566 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1567 {
1568         MsgData *data;
1569         const gchar *account_name;
1570         ModestMsgEditWindowPrivate *priv;
1571         TnyIterator *att_iter;
1572         
1573         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1574
1575         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1576                                                                         
1577         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1578         g_return_val_if_fail (account_name, NULL);
1579         
1580         
1581         /* don't free these (except from) */
1582         data = g_slice_new0 (MsgData);
1583         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1584                                                              account_name);
1585         data->account_name = g_strdup (account_name);
1586         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1587         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1588         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1589         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1590         if (priv->draft_msg) {
1591                 data->draft_msg = g_object_ref (priv->draft_msg);
1592         } else if (priv->outbox_msg) {
1593                 data->draft_msg = g_object_ref (priv->outbox_msg);
1594         } else {
1595                 data->draft_msg = NULL;
1596         }
1597
1598         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1599         GtkTextIter b, e;
1600         gtk_text_buffer_get_bounds (buf, &b, &e);
1601         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1602
1603         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1604                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1605         else
1606                 data->html_body = NULL;
1607
1608         /* deep-copy the data */
1609         att_iter = tny_list_create_iterator (priv->attachments);
1610         data->attachments = NULL;
1611         while (!tny_iterator_is_done (att_iter)) {
1612                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1613                 if (!(TNY_IS_MIME_PART(part))) {
1614                         g_warning ("strange data in attachment list");
1615                         g_object_unref (part);
1616                         tny_iterator_next (att_iter);
1617                         continue;
1618                 }
1619                 data->attachments = g_list_append (data->attachments,
1620                                                    part);
1621                 tny_iterator_next (att_iter);
1622         }
1623         g_object_unref (att_iter);
1624
1625         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1626         att_iter = tny_list_create_iterator (priv->images);
1627         data->images = NULL;
1628         while (!tny_iterator_is_done (att_iter)) {
1629                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1630                 const gchar *cid;
1631                 if (!(TNY_IS_MIME_PART(part))) {
1632                         g_warning ("strange data in attachment list");
1633                         g_object_unref (part);
1634                         tny_iterator_next (att_iter);
1635                         continue;
1636                 }
1637                 cid = tny_mime_part_get_content_id (part);
1638                 if (cid) {                      
1639                         gchar *image_tag_id;
1640                         GtkTextTag *image_tag;
1641                         GtkTextIter iter;
1642                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1643                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1644                         g_free (image_tag_id);
1645                         
1646                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1647                         if (image_tag && 
1648                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1649                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1650                                 data->images = g_list_append (data->images,
1651                                                               g_object_ref (part));
1652                 }
1653                 g_object_unref (part);
1654                 tny_iterator_next (att_iter);
1655         }
1656         g_object_unref (att_iter);
1657         
1658         data->priority_flags = priv->priority_flags;
1659
1660         return data;
1661 }
1662
1663
1664 static void
1665 unref_gobject (GObject *obj, gpointer data)
1666 {
1667         if (!G_IS_OBJECT(obj))
1668                 return;
1669         g_object_unref (obj);
1670 }
1671
1672 void 
1673 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1674                                                       MsgData *data)
1675 {
1676         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1677
1678         if (!data)
1679                 return;
1680
1681         g_free (data->to);
1682         g_free (data->cc);
1683         g_free (data->bcc);
1684         g_free (data->from);
1685         g_free (data->subject);
1686         g_free (data->plain_body);
1687         g_free (data->html_body);
1688         g_free (data->account_name);
1689         
1690         if (data->draft_msg != NULL) {
1691                 g_object_unref (data->draft_msg);
1692                 data->draft_msg = NULL;
1693         }
1694         
1695         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1696         g_list_free (data->attachments);
1697         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1698         g_list_free (data->images);
1699         
1700         g_slice_free (MsgData, data);
1701 }
1702
1703 void                    
1704 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1705                                        gint *parts_count,
1706                                        guint64 *parts_size)
1707 {
1708         ModestMsgEditWindowPrivate *priv;
1709
1710         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1711
1712         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1713
1714         /* TODO: add images */
1715         *parts_size += priv->images_size;
1716         *parts_count += priv->images_count;
1717
1718 }
1719
1720 ModestMsgEditFormat
1721 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1722 {
1723         gboolean rich_text;
1724         ModestMsgEditWindowPrivate *priv = NULL;
1725         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1726
1727         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1728
1729         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1730         if (rich_text)
1731                 return MODEST_MSG_EDIT_FORMAT_HTML;
1732         else
1733                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1734 }
1735
1736 void
1737 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1738                                    ModestMsgEditFormat format)
1739 {
1740         ModestMsgEditWindowPrivate *priv;
1741
1742         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1743         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1744
1745         switch (format) {
1746         case MODEST_MSG_EDIT_FORMAT_HTML:
1747                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1748                 break;
1749         case MODEST_MSG_EDIT_FORMAT_TEXT:
1750                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1751                 break;
1752         default:
1753                 g_return_if_reached ();
1754         }
1755 }
1756
1757 ModestMsgEditFormatState *
1758 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1759 {
1760         ModestMsgEditFormatState *format_state = NULL;
1761         ModestMsgEditWindowPrivate *priv;
1762         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1763
1764         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1765         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1766
1767         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1768
1769         format_state = g_new0 (ModestMsgEditFormatState, 1);
1770         format_state->bold = buffer_format->bold&0x1;
1771         format_state->italics = buffer_format->italic&0x1;
1772         format_state->bullet = buffer_format->bullet&0x1;
1773         format_state->color = buffer_format->color;
1774         format_state->font_size = buffer_format->font_size;
1775         format_state->font_family = wp_get_font_name (buffer_format->font);
1776         format_state->justification = buffer_format->justification;
1777         g_free (buffer_format);
1778
1779         return format_state;
1780  
1781 }
1782
1783 void
1784 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1785                                          const ModestMsgEditFormatState *format_state)
1786 {
1787         ModestMsgEditWindowPrivate *priv;
1788         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1789         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1790         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1791         g_return_if_fail (format_state != NULL);
1792
1793         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1794         gtk_widget_grab_focus (priv->msg_body);
1795         buffer_format->bold = (format_state->bold != FALSE);
1796         buffer_format->italic = (format_state->italics != FALSE);
1797         buffer_format->color = format_state->color;
1798         buffer_format->font_size = format_state->font_size;
1799         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1800         buffer_format->justification = format_state->justification;
1801         buffer_format->bullet = format_state->bullet;
1802
1803         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1804
1805         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1806         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1807         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1808         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1809         buffer_format->cs.font = (buffer_format->font != current_format->font);
1810         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1811         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1812
1813         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1814         if (buffer_format->cs.bold) {
1815                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1816                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1817         }
1818         if (buffer_format->cs.italic) {
1819                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1820                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1821         }
1822         if (buffer_format->cs.color) {
1823                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1824                                               GINT_TO_POINTER (&(buffer_format->color)));
1825         }
1826         if (buffer_format->cs.font_size) {
1827                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1828                                               GINT_TO_POINTER (buffer_format->font_size));
1829         }
1830         if (buffer_format->cs.justification) {
1831                 switch (buffer_format->justification) {
1832                 case GTK_JUSTIFY_LEFT:
1833                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1834                                                       GINT_TO_POINTER(TRUE));
1835                         break;
1836                 case GTK_JUSTIFY_CENTER:
1837                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1838                                                       GINT_TO_POINTER(TRUE));
1839                         break;
1840                 case GTK_JUSTIFY_RIGHT:
1841                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1842                                                       GINT_TO_POINTER(TRUE));
1843                         break;
1844                 default:
1845                         break;
1846                 }
1847                         
1848         }
1849         if (buffer_format->cs.font) {
1850                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1851                                               GINT_TO_POINTER (buffer_format->font));
1852         }
1853         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1854         if (buffer_format->cs.bullet) {
1855                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1856                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1857         }
1858 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1859         
1860         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1861         
1862         g_free (buffer_format);
1863         g_free (current_format);
1864
1865         /* Check dimming rules */
1866         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1867         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1868 }
1869
1870 static void
1871 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1872 {
1873         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1874         GtkAction *action;
1875         ModestWindowPrivate *parent_priv;
1876         ModestMsgEditWindowPrivate *priv;
1877         GtkWidget *new_size_menuitem;
1878         GtkWidget *new_font_menuitem;
1879         
1880         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1881         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1882
1883         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1884                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1885                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1886                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1887         } else {
1888                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1889                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1890                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1891         }
1892
1893         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1894
1895         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1896         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1897
1898         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1899         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1900
1901 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1902 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1903
1904         action = NULL;
1905         switch (buffer_format->justification)
1906         {
1907         case GTK_JUSTIFY_LEFT:
1908                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1909                 break;
1910         case GTK_JUSTIFY_CENTER:
1911                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1912                 break;
1913         case GTK_JUSTIFY_RIGHT:
1914                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1915                 break;
1916         default:
1917                 break;
1918         }
1919         
1920         if (action != NULL)
1921                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1922         
1923         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1924                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1925                                          window);
1926         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1927         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1928                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1929                                            window);
1930
1931         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1932                                                       buffer_format->font_size))->data);
1933         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1934                 GtkWidget *label;
1935                 gchar *markup;
1936
1937                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1938                 markup = g_strconcat ("<span font_family='Sans'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1939                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1940                 g_free (markup);
1941                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1942                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1943                                                  window);
1944                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1945                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1946                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1947                                                    window);
1948         }
1949
1950         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1951                                                       buffer_format->font))->data);
1952         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1953                 GtkWidget *label;
1954                 gchar *markup;
1955
1956                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1957                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1958                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1959                 g_free (markup);
1960                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1961                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1962                                                  window);
1963                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1964                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1965                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1966                                                    window);
1967         }
1968
1969         g_free (buffer_format);
1970
1971 }
1972
1973 #ifdef MODEST_HILDON_VERSION_0
1974 void
1975 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1976 {
1977         
1978         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1979         ModestMsgEditWindowPrivate *priv;
1980         GtkWidget *dialog = NULL;
1981         gint response;
1982         GdkColor *new_color = NULL;
1983
1984         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1985         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1986         
1987         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1988         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1989         g_free (buffer_format);
1990
1991         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1992                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1993                 if (new_color != NULL) {
1994                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1995                                                       (gpointer) new_color);
1996                 }
1997         }
1998         gtk_widget_destroy (dialog);
1999 }
2000
2001
2002 void
2003 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2004 {
2005         
2006         ModestMsgEditWindowPrivate *priv;
2007         GtkWidget *dialog = NULL;
2008         gint response;
2009         GdkColor *old_color = NULL;
2010         const GdkColor *new_color = NULL;
2011         
2012         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2013         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2014         
2015         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2016         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2017
2018         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2019                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2020                 if (new_color != NULL)
2021                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2022         }
2023         gtk_widget_destroy (dialog);
2024
2025 }
2026
2027 #else 
2028 void
2029 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2030 {
2031         
2032         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2033         ModestMsgEditWindowPrivate *priv;
2034         GtkWidget *dialog = NULL;
2035
2036         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2037         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2038                 
2039         dialog = hildon_color_chooser_new ();
2040         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2041         g_free (buffer_format);
2042
2043         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2044                 GdkColor col;
2045                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2046                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2047                                               (gpointer) &col);
2048         }
2049         gtk_widget_destroy (dialog);
2050 }
2051
2052
2053 void
2054 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2055 {
2056         
2057         ModestMsgEditWindowPrivate *priv;
2058         GtkWidget *dialog = NULL;
2059         GdkColor *old_color = NULL;
2060         
2061         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2062         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2063         
2064         dialog = hildon_color_chooser_new ();
2065         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2066
2067         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2068                 GdkColor col;
2069                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2070                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2071         }
2072         gtk_widget_destroy (dialog);
2073 }
2074
2075 #endif /*!MODEST_HILDON_VERSION_0*/
2076
2077
2078
2079 static TnyStream*
2080 create_stream_for_uri (const gchar* uri)
2081 {
2082         if (!uri)
2083                 return NULL;
2084                 
2085         TnyStream *result = NULL;
2086
2087         GnomeVFSHandle *handle = NULL;
2088         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2089         if (test == GNOME_VFS_OK) {
2090                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2091                 /* Streams over OBEX (Bluetooth) are not seekable but
2092                  * we expect them to be (we might need to read them
2093                  * several times). So if this is a Bluetooth URI just
2094                  * read the whole file into memory (this is not a fast
2095                  * protocol so we can assume that these files are not
2096                  * going to be very big) */
2097                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2098                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2099                         TnyStream *memstream = tny_camel_mem_stream_new ();
2100                         tny_stream_write_to_stream (vfssstream, memstream);
2101                         g_object_unref (vfssstream);
2102                         result = memstream;
2103                 } else {
2104                         result = vfssstream;
2105                 }
2106         }
2107         
2108         return result;
2109 }
2110
2111 void
2112 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2113 {
2114         
2115         ModestMsgEditWindowPrivate *priv;
2116         GtkWidget *dialog = NULL;
2117         gint response = 0;
2118         GSList *uris = NULL;
2119         GSList *uri_node = NULL;
2120         
2121         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2122         
2123         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2124         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2125         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2126
2127         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2128
2129         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2130                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2131
2132         response = gtk_dialog_run (GTK_DIALOG (dialog));
2133         switch (response) {
2134         case GTK_RESPONSE_OK:
2135                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2136                 break;
2137         default:
2138                 break;
2139         }
2140         gtk_widget_destroy (dialog);
2141
2142         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2143                 const gchar *uri;
2144                 GnomeVFSHandle *handle = NULL;
2145                 GnomeVFSResult result;
2146                 GtkTextIter position;
2147                 GtkTextMark *insert_mark;
2148
2149                 uri = (const gchar *) uri_node->data;
2150                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2151                 if (result == GNOME_VFS_OK) {
2152                         GdkPixbuf *pixbuf;
2153                         GnomeVFSFileInfo *info;
2154                         gchar *filename, *basename, *escaped_filename;
2155                         TnyMimePart *mime_part;
2156                         gchar *content_id;
2157                         const gchar *mime_type = NULL;
2158                         GnomeVFSURI *vfs_uri;
2159                         guint64 stream_size;
2160
2161                         gnome_vfs_close (handle);
2162                         vfs_uri = gnome_vfs_uri_new (uri);
2163
2164                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2165                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2166                         g_free (escaped_filename);
2167                         gnome_vfs_uri_unref (vfs_uri);
2168                         info = gnome_vfs_file_info_new ();
2169
2170                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2171                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2172                             == GNOME_VFS_OK)
2173                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2174
2175                         mime_part = tny_platform_factory_new_mime_part
2176                                 (modest_runtime_get_platform_factory ());
2177                                 
2178                         TnyStream *stream = create_stream_for_uri (uri);
2179
2180                         if (stream == NULL) {
2181
2182                                 modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2183                                 
2184                                 g_object_unref (mime_part);
2185                                 gnome_vfs_file_info_unref (info);
2186                                 continue;
2187                         }
2188
2189                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2190                         
2191                         content_id = g_strdup_printf ("%d", priv->next_cid);
2192                         tny_mime_part_set_content_id (mime_part, content_id);
2193                         g_free (content_id);
2194                         priv->next_cid++;
2195                         
2196                         basename = g_path_get_basename (filename);
2197                         tny_mime_part_set_filename (mime_part, basename);
2198                         g_free (basename);
2199
2200                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2201                         
2202                         if (pixbuf != NULL) {
2203                                 priv->images_size += stream_size;
2204                                 priv->images_count ++;
2205                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2206                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2207                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2208                                 g_object_unref (pixbuf);
2209                         } 
2210
2211                         tny_list_prepend (priv->images, (GObject *) mime_part);
2212                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2213                         g_free (filename);
2214                         g_object_unref (mime_part);
2215                         gnome_vfs_file_info_unref (info);
2216
2217                 }
2218         }
2219
2220
2221 }
2222
2223 void
2224 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2225 {       
2226         GtkWidget *dialog = NULL;
2227         gint response = 0;
2228         GSList *uris = NULL;
2229         GSList *uri_node;
2230         GnomeVFSFileSize total_size, allowed_size;
2231         ModestMsgEditWindowPrivate *priv;
2232         gint att_num;
2233         guint64 att_size;
2234
2235         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2236                 
2237         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2238
2239         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2240                 return;
2241         
2242         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2243         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2244         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2245         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog), GTK_WINDOW (window));
2246
2247         response = gtk_dialog_run (GTK_DIALOG (dialog));
2248         switch (response) {
2249         case GTK_RESPONSE_OK:
2250                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2251                 break;
2252         default:
2253                 break;
2254         }
2255         gtk_widget_destroy (dialog);
2256
2257         /* allowed size is the maximum size - what's already there */
2258         modest_attachments_view_get_sizes (
2259                 MODEST_ATTACHMENTS_VIEW (priv->attachments_view), 
2260                 &att_num, &att_size);
2261         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2262
2263         total_size = 0;
2264         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2265
2266                 const gchar *uri = (const gchar *) uri_node->data;
2267                 
2268                 total_size += modest_msg_edit_window_attach_file_one 
2269                         (window, uri, allowed_size);
2270                 
2271                 if (total_size > allowed_size) {
2272                         g_warning ("%s: total size: %u", 
2273                                    __FUNCTION__, (unsigned int)total_size);
2274                         break;
2275                 }
2276
2277                 allowed_size -= total_size;
2278                 
2279
2280         }
2281         g_slist_foreach (uris, (GFunc) g_free, NULL);
2282         g_slist_free (uris);
2283 }
2284
2285
2286 GnomeVFSFileSize
2287 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2288                                         const gchar *uri, 
2289                                         GnomeVFSFileSize allowed_size)
2290
2291 {
2292         GnomeVFSHandle *handle = NULL;
2293         ModestMsgEditWindowPrivate *priv;
2294         GnomeVFSResult result;
2295         GnomeVFSFileSize size = 0;
2296         g_return_val_if_fail (window, 0);
2297         g_return_val_if_fail (uri, 0);
2298                 
2299         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2300         
2301         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2302         if (result == GNOME_VFS_OK) {
2303                 TnyMimePart *mime_part;
2304                 TnyStream *stream;
2305                 const gchar *mime_type = NULL;
2306                 gchar *basename;
2307                 gchar *escaped_filename;
2308                 gchar *filename;
2309                 gchar *content_id;
2310                 GnomeVFSFileInfo *info;
2311                 GnomeVFSURI *vfs_uri;
2312
2313                 gnome_vfs_close (handle);
2314                 vfs_uri = gnome_vfs_uri_new (uri);
2315                 
2316
2317                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2318                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2319                 g_free (escaped_filename);
2320                 gnome_vfs_uri_unref (vfs_uri);
2321
2322                 info = gnome_vfs_file_info_new ();
2323                 
2324                 if (gnome_vfs_get_file_info (uri, 
2325                                              info, 
2326                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2327                     == GNOME_VFS_OK)
2328                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2329                 mime_part = tny_platform_factory_new_mime_part
2330                         (modest_runtime_get_platform_factory ());
2331                 
2332                 /* try to get the attachment's size; this may fail for weird
2333                  * file systems, like obex, upnp... */
2334                 if (allowed_size != 0 &&
2335                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2336                         size = info->size;
2337                         if (size > allowed_size) {
2338                                 modest_platform_information_banner (NULL, NULL, 
2339                                                                     dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2340                                 return 0;
2341                         }
2342                 } else
2343                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2344                 
2345                 stream = create_stream_for_uri (uri);
2346                 
2347                 if (stream == NULL) {
2348
2349                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2350
2351                         g_object_unref (mime_part);
2352                         gnome_vfs_file_info_unref (info);
2353                         return 0;
2354                 }
2355
2356                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2357                 g_object_unref (stream);
2358                 
2359                 content_id = g_strdup_printf ("%d", priv->next_cid);
2360                 tny_mime_part_set_content_id (mime_part, content_id);
2361                 g_free (content_id);
2362                 priv->next_cid++;
2363                 
2364                 basename = g_path_get_basename (filename);
2365                 tny_mime_part_set_filename (mime_part, basename);
2366                 g_free (basename);
2367                 
2368                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2369                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2370                                                         mime_part,
2371                                                         info->size == 0, info->size);
2372                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2373                 gtk_widget_show_all (priv->attachments_caption);
2374                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2375                 g_free (filename);
2376                 g_object_unref (mime_part);
2377                 gnome_vfs_file_info_unref (info);
2378         }
2379
2380         return size;
2381 }
2382
2383 void
2384 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2385                                            TnyList *att_list)
2386 {
2387         ModestMsgEditWindowPrivate *priv;
2388         TnyIterator *iter;
2389
2390         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2391         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2392
2393         if (att_list == NULL) {
2394                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2395         } else {
2396                 g_object_ref (att_list);
2397         }
2398
2399         if (tny_list_get_length (att_list) == 0) {
2400                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2401         } else {
2402                 gboolean dialog_response;
2403                 gchar *message = NULL;
2404                 gchar *filename = NULL;
2405
2406                 if (tny_list_get_length (att_list) == 1) {
2407                         TnyMimePart *part;
2408                         iter = tny_list_create_iterator (att_list);
2409                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2410                         g_object_unref (iter);
2411                         if (TNY_IS_MSG (part)) {
2412                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2413                                 if (header) {
2414                                         filename = tny_header_dup_subject (header);
2415                                         g_object_unref (header);
2416                                 }
2417                                 if (filename == NULL) {
2418                                         filename = g_strdup (_("mail_va_no_subject"));
2419                                 }
2420                         } else {
2421                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2422                         }
2423                         g_object_unref (part);
2424                 } else {
2425                         filename = g_strdup ("");
2426                 }
2427                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2428                                                     tny_list_get_length (att_list)), filename);
2429                 g_free (filename);
2430
2431                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), message);
2432                 g_free (message);
2433
2434                 if (dialog_response != GTK_RESPONSE_OK) {
2435                         g_object_unref (att_list);
2436                         return;
2437                 }
2438                 hildon_banner_show_information (NULL, NULL, _("mcen_me_inbox_remove_attachments"));
2439                 
2440                 for (iter = tny_list_create_iterator (att_list);
2441                      !tny_iterator_is_done (iter);
2442                      tny_iterator_next (iter)) {
2443                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2444                         const gchar *att_id;
2445                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2446
2447                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2448                                                                    mime_part);
2449                         if (tny_list_get_length (priv->attachments) == 0)
2450                                 gtk_widget_hide (priv->attachments_caption);
2451                         att_id = tny_mime_part_get_content_id (mime_part);
2452                         if (att_id != NULL)
2453                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2454                                                                  att_id);
2455                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2456                         g_object_unref (mime_part);
2457                 }
2458                 g_object_unref (iter);
2459         }
2460
2461         g_object_unref (att_list);
2462
2463         /* if the last attachment has been removed, focus the Subject: field */
2464         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2465                 gtk_widget_grab_focus (priv->subject_field);
2466 }
2467
2468 static void
2469 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2470                                             gpointer userdata)
2471 {
2472         ModestMsgEditWindowPrivate *priv;
2473         GdkColor *new_color;
2474         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2475         
2476 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2477         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2478 #else 
2479         GdkColor col;
2480         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2481         new_color = &col;
2482 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2483
2484         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2485         
2486         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2487
2488 }
2489
2490 static void
2491 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2492                                     gpointer userdata)
2493 {
2494         ModestMsgEditWindowPrivate *priv;
2495         gint new_size_index;
2496         ModestMsgEditWindow *window;
2497         GtkWidget *label;
2498         
2499         window = MODEST_MSG_EDIT_WINDOW (userdata);
2500         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2501         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2502
2503         if (gtk_check_menu_item_get_active (menu_item)) {
2504                 gchar *markup;
2505                 WPTextBufferFormat format;
2506
2507                 memset (&format, 0, sizeof (format));
2508                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2509
2510                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2511                 
2512                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2513                 format.cs.font_size = TRUE;
2514                 format.cs.text_position = TRUE;
2515                 format.cs.font = TRUE;
2516                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2517 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2518
2519                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2520                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2521                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2522                 
2523                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2524                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2525                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2526                 g_free (markup);
2527         }
2528 }
2529
2530 static void
2531 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2532                                     gpointer userdata)
2533 {
2534         ModestMsgEditWindowPrivate *priv;
2535         gint new_font_index;
2536         ModestMsgEditWindow *window;
2537         GtkWidget *label;
2538         
2539         window = MODEST_MSG_EDIT_WINDOW (userdata);
2540         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2541         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2542
2543         if (gtk_check_menu_item_get_active (menu_item)) {
2544                 gchar *markup;
2545
2546                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2547                 
2548                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2549
2550                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2551                                                    GINT_TO_POINTER(new_font_index)))
2552                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2553                 
2554                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2555                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2556                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2557                 g_free (markup);
2558         }
2559 }
2560
2561 void
2562 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2563                                 gboolean show)
2564 {
2565         ModestMsgEditWindowPrivate *priv = NULL;
2566         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2567
2568         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2569         if (!priv->update_caption_visibility)
2570                 return;
2571
2572         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2573         if (show)
2574                 gtk_widget_show (priv->cc_caption);
2575         else
2576                 gtk_widget_hide (priv->cc_caption);
2577
2578         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2579 }
2580
2581 void
2582 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2583                                  gboolean show)
2584 {
2585         ModestMsgEditWindowPrivate *priv = NULL;
2586         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2587
2588         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2589         if (!priv->update_caption_visibility)
2590                 return;
2591
2592         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2593         if (show)
2594                 gtk_widget_show (priv->bcc_caption);
2595         else
2596                 gtk_widget_hide (priv->bcc_caption);
2597
2598         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2599 }
2600
2601 static void
2602 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2603                                          ModestRecptEditor *editor)
2604 {
2605         ModestMsgEditWindowPrivate *priv;
2606
2607         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2608         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2609         
2610         /* we check for low-mem; in that case, show a warning, and don't allow
2611          * for the addressbook
2612          */
2613         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2614                 return;
2615
2616         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2617
2618         if (editor == NULL) {
2619                 GtkWidget *view_focus;
2620                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2621
2622                 /* This code should be kept in sync with ModestRecptEditor. The
2623                    textview inside the recpt editor is the one that really gets the
2624                    focus. As it's inside a scrolled window, and this one inside the
2625                    hbox recpt editor inherits from, we'll need to go up in the 
2626                    hierarchy to know if the text view is part of the recpt editor
2627                    or if it's a different text entry */
2628
2629                 if (gtk_widget_get_parent (view_focus)) {
2630                         GtkWidget *first_parent;
2631
2632                         first_parent = gtk_widget_get_parent (view_focus);
2633                         if (gtk_widget_get_parent (first_parent) && 
2634                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2635                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2636                         }
2637                 }
2638
2639                 if (editor == NULL)
2640                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2641
2642         }
2643
2644         modest_address_book_select_addresses (editor);
2645
2646 }
2647
2648 void
2649 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2650 {
2651         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2652
2653         modest_msg_edit_window_open_addressbook (window, NULL);
2654 }
2655
2656 static void
2657 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2658                                      gboolean show_toolbar)
2659 {
2660         ModestWindowPrivate *parent_priv;
2661
2662         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2663         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2664
2665         /* We can not just use the code of
2666            modest_msg_edit_window_setup_toolbar because it has a
2667            mixture of both initialization and creation code. */
2668         if (show_toolbar)
2669                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2670         else
2671                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2672 }
2673
2674 void
2675 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2676                                            TnyHeaderFlags priority_flags)
2677 {
2678         ModestMsgEditWindowPrivate *priv;
2679         ModestWindowPrivate *parent_priv;
2680
2681         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2682
2683         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2684         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2685
2686         if (priv->priority_flags != priority_flags) {
2687                 GtkAction *priority_action = NULL;
2688
2689                 priv->priority_flags = priority_flags;
2690
2691                 switch (priority_flags) {
2692                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2693                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2694                                                       MODEST_HEADER_ICON_HIGH, 
2695                                                       HILDON_ICON_SIZE_XSMALL);
2696                         gtk_widget_show (priv->priority_icon);
2697                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2698                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2699                         break;
2700                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2701                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2702                                                       MODEST_HEADER_ICON_LOW,
2703                                                       HILDON_ICON_SIZE_XSMALL);
2704                         gtk_widget_show (priv->priority_icon);
2705                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2706                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2707                         break;
2708                 default:
2709                         gtk_widget_hide (priv->priority_icon);
2710                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2711                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2712                         break;
2713                 }
2714                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2715                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2716         }
2717 }
2718
2719 void
2720 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2721                                         gint file_format)
2722 {
2723         ModestMsgEditWindowPrivate *priv;
2724         ModestWindowPrivate *parent_priv;
2725         gint current_format;
2726
2727         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2728
2729         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2730         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2731
2732         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2733                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2734
2735         if (current_format != file_format) {
2736                 switch (file_format) {
2737                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2738                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2739                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2740                         break;
2741                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2742                 {
2743                         GtkWidget *dialog;
2744                         gint response;
2745                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2746                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2747                         gtk_widget_destroy (dialog);
2748                         if (response == GTK_RESPONSE_OK) {
2749                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2750                         } else {
2751                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2752                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2753                         }
2754                 }
2755                         break;
2756                 }
2757                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2758                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2759                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2760         }
2761 }
2762
2763 void
2764 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2765 {
2766         GtkWidget *dialog;
2767         ModestMsgEditWindowPrivate *priv;
2768         WPTextBufferFormat oldfmt, fmt;
2769         gint old_position = 0;
2770         gint response = 0;
2771         gint position = 0;
2772         gint font_size;
2773         GdkColor *color = NULL;
2774         gboolean bold, bold_set, italic, italic_set;
2775         gboolean underline, underline_set;
2776         gboolean strikethrough, strikethrough_set;
2777         gboolean position_set;
2778         gboolean font_size_set, font_set, color_set;
2779         gchar *font_name;
2780
2781         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2782         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2783         
2784         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2785         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2786                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2787
2788         /* First we get the currently selected font information */
2789         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2790
2791         switch (oldfmt.text_position) {
2792         case TEXT_POSITION_NORMAL:
2793                 old_position = 0;
2794                 break;
2795         case TEXT_POSITION_SUPERSCRIPT:
2796                 old_position = 1;
2797                 break;
2798         default:
2799                 old_position = -1;
2800                 break;
2801         }
2802
2803         g_object_set (G_OBJECT (dialog),
2804                       "bold", oldfmt.bold != FALSE,
2805                       "bold-set", !oldfmt.cs.bold,
2806                       "underline", oldfmt.underline != FALSE,
2807                       "underline-set", !oldfmt.cs.underline,
2808                       "italic", oldfmt.italic != FALSE,
2809                       "italic-set", !oldfmt.cs.italic,
2810                       "strikethrough", oldfmt.strikethrough != FALSE,
2811                       "strikethrough-set", !oldfmt.cs.strikethrough,
2812                       "color", &oldfmt.color,
2813                       "color-set", !oldfmt.cs.color,
2814                       "size", wp_font_size[oldfmt.font_size],
2815                       "size-set", !oldfmt.cs.font_size,
2816                       "position", old_position,
2817                       "position-set", !oldfmt.cs.text_position,
2818                       "family", wp_get_font_name (oldfmt.font),
2819                       "family-set", !oldfmt.cs.font,
2820                       NULL);
2821
2822         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2823                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2824         gtk_widget_show_all (dialog);
2825         priv->font_dialog = dialog;
2826         response = gtk_dialog_run (GTK_DIALOG (dialog));
2827         priv->font_dialog = NULL;
2828         if (response == GTK_RESPONSE_OK) {
2829
2830                 g_object_get( dialog,
2831                               "bold", &bold,
2832                               "bold-set", &bold_set,
2833                               "underline", &underline,
2834                               "underline-set", &underline_set,
2835                               "italic", &italic,
2836                               "italic-set", &italic_set,
2837                               "strikethrough", &strikethrough,
2838                               "strikethrough-set", &strikethrough_set,
2839                               "color", &color,
2840                               "color-set", &color_set,
2841                               "size", &font_size,
2842                               "size-set", &font_size_set,
2843                               "family", &font_name,
2844                               "family-set", &font_set,
2845                               "position", &position,
2846                               "position-set", &position_set,
2847                               NULL );
2848                 
2849         }       
2850
2851         if (response == GTK_RESPONSE_OK) {
2852                 memset(&fmt, 0, sizeof(fmt));
2853                 if (bold_set) {
2854                         fmt.bold = bold;
2855                         fmt.cs.bold = TRUE;
2856                 }
2857                 if (italic_set) {
2858                         fmt.italic = italic;
2859                         fmt.cs.italic = TRUE;
2860                 }
2861                 if (underline_set) {
2862                         fmt.underline = underline;
2863                         fmt.cs.underline = TRUE;
2864                 }
2865                 if (strikethrough_set) {
2866                         fmt.strikethrough = strikethrough;
2867                         fmt.cs.strikethrough = TRUE;
2868                 }
2869                 if (position_set) {
2870                         fmt.text_position =
2871                                 ( position == 0 )
2872                                 ? TEXT_POSITION_NORMAL
2873                                 : ( ( position == 1 )
2874                                     ? TEXT_POSITION_SUPERSCRIPT
2875                                     : TEXT_POSITION_SUBSCRIPT );
2876                         fmt.cs.text_position = TRUE;
2877                         fmt.font_size = oldfmt.font_size;
2878                 }
2879                 if (color_set) {
2880                         fmt.color = *color;
2881                         fmt.cs.color = TRUE;
2882                 }
2883                 if (font_set) {
2884                         fmt.font = wp_get_font_index(font_name,
2885                                                      DEFAULT_FONT);
2886                         fmt.cs.font = TRUE;
2887                 }
2888                 g_free(font_name);
2889                 if (font_size_set) {
2890                         fmt.cs.font_size = TRUE;
2891                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2892                 }
2893                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2894                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2895         }
2896         gtk_widget_destroy (dialog);
2897         
2898         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2899 }
2900
2901 void
2902 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2903 {
2904         ModestMsgEditWindowPrivate *priv;
2905
2906         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2907         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2908         
2909         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2910
2911         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2912         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2913 }
2914
2915 void
2916 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2917 {
2918         ModestMsgEditWindowPrivate *priv;
2919
2920         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2921         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2922         
2923         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2924
2925         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2926         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2927
2928 }
2929
2930 static void  
2931 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2932 {
2933         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2934
2935         priv->can_undo = can_undo;
2936 }
2937
2938 static void  
2939 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2940 {
2941         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2942
2943         priv->can_redo = can_redo;
2944 }
2945
2946 gboolean            
2947 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2948 {
2949         ModestMsgEditWindowPrivate *priv;
2950         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2951         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2952
2953         return priv->can_undo;
2954 }
2955
2956 gboolean            
2957 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2958 {
2959         ModestMsgEditWindowPrivate *priv;
2960         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2961         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2962
2963         return priv->can_redo;
2964 }
2965
2966
2967 static void
2968 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2969 {
2970         GtkTextIter iter;
2971         GtkTextIter match_start, match_end;
2972
2973         if (image_id == NULL)
2974                 return;
2975
2976         gtk_text_buffer_get_start_iter (buffer, &iter);
2977
2978         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2979                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2980                 GSList *node;
2981                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2982                         GtkTextTag *tag = (GtkTextTag *) node->data;
2983                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2984                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2985                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2986                                         gint offset;
2987                                         offset = gtk_text_iter_get_offset (&match_start);
2988                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2989                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2990                                 }
2991                         }
2992                 }
2993                 gtk_text_iter_forward_char (&iter);
2994         }
2995 }
2996
2997 gboolean
2998 message_is_empty (ModestMsgEditWindow *window)
2999 {
3000         ModestMsgEditWindowPrivate *priv = NULL;
3001
3002         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3003         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3004
3005         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3006          * so we can ignore markup.
3007          */
3008         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3009         gint count = 0;
3010         if (buf)
3011                 count = gtk_text_buffer_get_char_count (buf);
3012
3013         return count == 0;
3014 }
3015
3016 static gboolean
3017 msg_body_focus (GtkWidget *focus,
3018                 GdkEventFocus *event,
3019                 gpointer userdata)
3020 {
3021         
3022         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3023         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3024         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3025         return FALSE;
3026 }
3027
3028 static void
3029 recpt_field_changed (GtkTextBuffer *buffer,
3030                   ModestMsgEditWindow *editor)
3031 {
3032         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3033         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3034 }
3035
3036 static void
3037 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3038 {
3039         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3040         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3041 }
3042
3043 void
3044 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3045                                      gboolean modified)
3046 {
3047         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3048         GtkTextBuffer *buffer;
3049
3050         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3051         gtk_text_buffer_set_modified (buffer, modified);
3052         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3053         gtk_text_buffer_set_modified (buffer, modified);
3054         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3055         gtk_text_buffer_set_modified (buffer, modified);
3056         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3057 }
3058
3059 gboolean
3060 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3061 {
3062         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3063         const char *account_name;
3064         GtkTextBuffer *buffer;
3065
3066         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3067         if (gtk_text_buffer_get_modified (buffer))
3068                 return TRUE;
3069         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3070         if (gtk_text_buffer_get_modified (buffer))
3071                 return TRUE;
3072         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3073         if (gtk_text_buffer_get_modified (buffer))
3074                 return TRUE;
3075         if (gtk_text_buffer_get_modified (priv->text_buffer))
3076                 return TRUE;
3077         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3078         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3079                 return TRUE;
3080         }
3081
3082         return FALSE;
3083 }
3084
3085
3086
3087
3088 gboolean
3089 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3090 {
3091         ModestMsgEditWindowPrivate *priv = NULL;
3092         
3093         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3094         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3095
3096         /* check if there's no recipient added */
3097         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3098             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3099             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3100                 /* no recipient contents, then select contacts */
3101                 modest_msg_edit_window_open_addressbook (window, NULL);
3102                 return FALSE;
3103         }
3104
3105         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3106                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3107                 return FALSE;
3108         }
3109         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3110                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3111                 return FALSE;
3112         }
3113         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3114                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3115                 return FALSE;
3116         }
3117
3118         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3119             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3120                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3121
3122         return TRUE;
3123
3124 }
3125
3126 static void
3127 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3128                                                ModestMsgEditWindow *window)
3129 {
3130         modest_msg_edit_window_offer_attach_file (window);
3131 }
3132
3133 const gchar *
3134 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3135 {
3136         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3137
3138         return priv->clipboard_text;
3139 }
3140
3141 static void
3142 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3143                                                GdkEvent *event,
3144                                                ModestMsgEditWindow *window)
3145 {
3146         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3147         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3148         gchar *text = NULL;
3149         if (!GTK_WIDGET_VISIBLE (window))
3150                 return;
3151
3152         g_object_ref (window);
3153         text = gtk_clipboard_wait_for_text (selection_clipboard);
3154
3155         if (priv->clipboard_text != NULL) {
3156                 g_free (priv->clipboard_text);
3157         }
3158         priv->clipboard_text = text;
3159
3160         if (GTK_WIDGET_VISIBLE (window)) {
3161                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3162         }
3163         g_object_unref (window);
3164 }
3165
3166 static gboolean clipboard_owner_change_idle (gpointer userdata)
3167 {
3168         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3169         ModestMsgEditWindowPrivate *priv;
3170
3171         gdk_threads_enter ();
3172         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3173         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3174
3175         priv->clipboard_owner_idle = 0;
3176         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3177         gdk_threads_leave ();
3178
3179         return FALSE;
3180 }
3181
3182 static void
3183 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3184 {
3185         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3186         if (priv->clipboard_owner_idle == 0) {
3187                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3188         }
3189 }
3190
3191 static void 
3192 subject_field_move_cursor (GtkEntry *entry,
3193                            GtkMovementStep step,
3194                            gint a1,
3195                            gboolean a2,
3196                            gpointer window)
3197 {
3198         if (!GTK_WIDGET_VISIBLE (window))
3199                 return;
3200
3201         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3202 }
3203
3204 static void 
3205 update_window_title (ModestMsgEditWindow *window)
3206 {
3207         ModestMsgEditWindowPrivate *priv = NULL;
3208         const gchar *subject;
3209
3210         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3211         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3212         if (subject == NULL || subject[0] == '\0')
3213                 subject = _("mail_va_new_email");
3214
3215         gtk_window_set_title (GTK_WINDOW (window), subject);
3216
3217 }
3218
3219 static void  
3220 subject_field_changed (GtkEditable *editable, 
3221                        ModestMsgEditWindow *window)
3222 {
3223         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3224         update_window_title (window);
3225         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3226         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3227         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3228 }
3229
3230 static void  
3231 subject_field_insert_text (GtkEditable *editable, 
3232                            gchar *new_text,
3233                            gint new_text_length,
3234                            gint *position,
3235                            ModestMsgEditWindow *window)
3236 {
3237         GString *result = g_string_new ("");
3238         gchar *current;
3239         gint result_len = 0;
3240         const gchar *entry_text = NULL;
3241         gint old_length;
3242
3243         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3244         old_length = g_utf8_strlen (entry_text, -1);
3245
3246         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3247                 gunichar c = g_utf8_get_char_validated (current, 8);
3248                 /* Invalid unichar, stop */
3249                 if (c == -1)
3250                         break;
3251                 /* a bullet */
3252                 if (c == 0x2022)
3253                         continue;
3254                 result = g_string_append_unichar (result, c);
3255                 result_len++;
3256         }
3257
3258         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3259                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3260                 if (result_len > 0)
3261                 {
3262                         /* Prevent endless recursion */
3263                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3264                         g_signal_emit_by_name (editable, "insert-text", 
3265                                                (gpointer) result->str, (gpointer) result->len,
3266                                                (gpointer) position, (gpointer) window);
3267                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3268                 }
3269         }
3270
3271         if (result_len + old_length > 1000) {
3272                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3273                                                 dgettext("hildon-common-strings",
3274                                                          "ckdg_ib_maximum_characters_reached"));
3275         }
3276         
3277         g_string_free (result, TRUE);
3278 }
3279
3280 void
3281 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3282                                             gboolean show)
3283 {
3284         ModestMsgEditWindowPrivate *priv = NULL;
3285
3286         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3287         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3288
3289         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3290
3291         if (show) {
3292                 gtk_widget_show_all (priv->find_toolbar);
3293                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3294         } else {
3295                 gtk_widget_hide_all (priv->find_toolbar);
3296                 gtk_widget_grab_focus (priv->msg_body);
3297         }
3298     
3299 }
3300
3301 static gboolean 
3302 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3303                                           const gchar *str,
3304                                           GtkTextIter *match_start,
3305                                           GtkTextIter *match_end)
3306 {
3307         GtkTextIter end_iter;
3308         gchar *str_casefold;
3309         gint str_chars_n;
3310         gchar *range_text;
3311         gchar *range_casefold;
3312         gint offset;
3313         gint range_chars_n;
3314         gboolean result = FALSE;
3315
3316         if (str == NULL)
3317                 return TRUE;
3318         
3319         /* get end iter */
3320         end_iter = *iter;
3321         gtk_text_iter_forward_to_end (&end_iter);
3322
3323         str_casefold = g_utf8_casefold (str, -1);
3324         str_chars_n = strlen (str);
3325
3326         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3327         range_casefold = g_utf8_casefold (range_text, -1);
3328         range_chars_n = strlen (range_casefold);
3329
3330         if (range_chars_n < str_chars_n) {
3331                 g_free (str_casefold);
3332                 g_free (range_text);
3333                 g_free (range_casefold);
3334                 return FALSE;
3335         }
3336
3337         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3338                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3339                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3340                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3341                         result = TRUE;
3342                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3343                                                       match_start, match_end, NULL);
3344                         g_free (found_text);
3345                 }
3346                 g_free (range_subtext);
3347                 if (result)
3348                         break;
3349         }
3350         g_free (str_casefold);
3351         g_free (range_text);
3352         g_free (range_casefold);
3353
3354         return result;
3355 }
3356
3357
3358 static void 
3359 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3360                                             ModestMsgEditWindow *window)
3361 {
3362         gchar *current_search = NULL;
3363         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3364         gboolean result;
3365         GtkTextIter selection_start, selection_end;
3366         GtkTextIter match_start, match_end;
3367         gboolean continue_search = FALSE;
3368
3369         if (message_is_empty (window)) {
3370                 g_free (priv->last_search);
3371                 priv->last_search = NULL;
3372                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3373                 return;
3374         }
3375
3376         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3377         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3378                 g_free (current_search);
3379                 g_free (priv->last_search);
3380                 priv->last_search = NULL;
3381                 /* Information banner about empty search */
3382                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3383                 return;
3384         }
3385
3386         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3387                 continue_search = TRUE;
3388         } else {
3389                 g_free (priv->last_search);
3390                 priv->last_search = g_strdup (current_search);
3391         }
3392
3393         if (continue_search) {
3394                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3395                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3396                                                                    &match_start, &match_end);
3397                 if (!result)
3398                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3399         } else {
3400                 GtkTextIter buffer_start;
3401                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3402                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3403                                                                    &match_start, &match_end);
3404                 if (!result)
3405                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3406         }
3407
3408         /* Mark as selected the string found in search */
3409         if (result) {
3410                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3411                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3412                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3413         } else {
3414                 g_free (priv->last_search);
3415                 priv->last_search = NULL;
3416         }
3417         g_free (current_search);
3418 }
3419
3420 static void
3421 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3422                                            ModestMsgEditWindow *window)
3423 {
3424         ModestMsgEditWindowPrivate *priv;
3425
3426         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3427
3428         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->find_toolbar_button), FALSE);
3429 }
3430
3431 gboolean 
3432 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3433 {
3434         ModestMsgEditWindowPrivate *priv;
3435
3436         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3437         return priv->sent;
3438 }
3439
3440 void 
3441 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3442                                  gboolean sent)
3443 {
3444         ModestMsgEditWindowPrivate *priv;
3445
3446         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3447         priv->sent = sent;
3448 }
3449
3450
3451 void            
3452 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3453                                   TnyMsg *draft)
3454 {
3455         ModestMsgEditWindowPrivate *priv;
3456         TnyHeader *header = NULL;
3457
3458         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3459         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3460
3461         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3462         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3463
3464         if (priv->draft_msg != NULL) {
3465                 g_object_unref (priv->draft_msg);
3466         }
3467
3468         if (draft != NULL) {
3469                 g_object_ref (draft);
3470                 header = tny_msg_get_header (draft);
3471                 if (priv->msg_uid) {
3472                         g_free (priv->msg_uid);
3473                         priv->msg_uid = NULL;
3474                 }
3475                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3476                 if (GTK_WIDGET_REALIZED (window)) {
3477                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3478                                 gtk_widget_destroy (GTK_WIDGET (window));
3479                                 return;
3480                         }
3481                 }
3482         }
3483
3484         priv->draft_msg = draft;
3485 }
3486
3487 static void  
3488 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3489                        GtkTextIter *start, GtkTextIter *end,
3490                        gpointer userdata)
3491 {
3492         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3493         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3494         gchar *tag_name;
3495
3496         if (tag == NULL) return;
3497         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3498         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3499                 replace_with_images (window, priv->images);
3500         }
3501 }
3502
3503 void                    
3504 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3505                                  TnyMimePart *part)
3506 {
3507         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3508
3509         g_return_if_fail (TNY_IS_MIME_PART (part));
3510         tny_list_prepend (priv->attachments, (GObject *) part);
3511         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3512         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3513         gtk_widget_show_all (priv->attachments_caption);
3514         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3515 }
3516
3517 const gchar*    
3518 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3519 {
3520         ModestMsgEditWindowPrivate *priv;
3521
3522         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3523         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3524
3525         return priv->msg_uid;
3526 }
3527
3528 GtkWidget *
3529 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3530                                          ModestMsgEditWindowWidgetType widget_type)
3531 {
3532         ModestMsgEditWindowPrivate *priv;
3533
3534         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3535         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3536
3537         switch (widget_type) {
3538         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3539                 return priv->msg_body;
3540                 break;
3541         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3542                 return priv->to_field;
3543                 break;
3544         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3545                 return priv->cc_field;
3546                 break;
3547         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3548                 return priv->bcc_field;
3549                 break;
3550         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3551                 return priv->subject_field;
3552                 break;
3553         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3554                 return priv->attachments_view;
3555                 break;
3556         default:
3557                 return NULL;
3558         }
3559 }
3560
3561 static void 
3562 remove_tags (WPTextBuffer *buffer)
3563 {
3564         GtkTextIter start, end;
3565
3566         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3567         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3568
3569         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3570 }
3571
3572 static void
3573 on_account_removed (TnyAccountStore *account_store, 
3574                     TnyAccount *account,
3575                     gpointer user_data)
3576 {
3577         /* Do nothing if it's a store account, because we use the
3578            transport to send the messages */
3579         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3580                 const gchar *parent_acc = NULL;
3581                 const gchar *our_acc = NULL;
3582
3583                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3584                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3585                 /* Close this window if I'm showing a message of the removed account */
3586                 if (strcmp (parent_acc, our_acc) == 0)
3587                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3588         }
3589 }
3590
3591 typedef struct _MessageSettingsHelper {
3592         ModestMsgEditWindow *window;
3593         GSList *priority_group;
3594         GtkWidget *align_picker;
3595 } MessageSettingsHelper;
3596
3597 static void
3598 on_priority_toggle (HildonCheckButton *button, 
3599                     MessageSettingsHelper *helper)
3600 {
3601         GSList *node;
3602         ModestMsgEditWindowPrivate *priv;
3603
3604         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3605         if (hildon_check_button_get_active (button)) {
3606
3607                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3608                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3609                         if ((node_button != button) &&
3610                             hildon_check_button_get_active (node_button)) {
3611                                 hildon_check_button_set_active (node_button, FALSE);
3612                         }
3613                         if (priv->priority_flags != (TnyHeaderFlags) g_object_get_data (G_OBJECT (button), "priority"))
3614                                 modest_msg_edit_window_set_priority_flags (helper->window,
3615                                                                            (TnyHeaderFlags) 
3616                                                                            g_object_get_data (G_OBJECT (button), 
3617                                                                                               "priority"));
3618                 }
3619
3620                 
3621         } else {
3622                 gboolean found = FALSE;
3623                 /* If no one is active, activate it again */
3624                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3625                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3626                         if (hildon_check_button_get_active (node_button)) {
3627                                 found = TRUE;
3628                                 break;
3629                         }
3630                 }
3631                 if (!found) {
3632                         hildon_check_button_set_active (button, TRUE);
3633                 }
3634         }
3635 }
3636
3637 static void
3638 on_format_picker_value_changed (HildonPickerButton *button,
3639                                 MessageSettingsHelper *helper)
3640 {
3641         ModestMsgEditFormat new_format, old_format;
3642         gint file_format;
3643
3644         switch (hildon_picker_button_get_active (button)) {
3645         case 1:
3646                 new_format = MODEST_MSG_EDIT_FORMAT_HTML;
3647                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
3648                 break;
3649         case 0:
3650         default:
3651                 new_format = MODEST_MSG_EDIT_FORMAT_TEXT;
3652                 file_format = MODEST_FILE_FORMAT_PLAIN_TEXT;
3653                 break;
3654         }
3655
3656         old_format = modest_msg_edit_window_get_format (helper->window);
3657         if (new_format != old_format) {
3658                 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (helper->window), file_format);
3659
3660                 switch (modest_msg_edit_window_get_format (helper->window)) {
3661                 case MODEST_MSG_EDIT_FORMAT_TEXT:
3662                         hildon_picker_button_set_active (button, 0);
3663                         gtk_widget_set_sensitive (helper->align_picker, FALSE);
3664                         break;
3665                 case MODEST_MSG_EDIT_FORMAT_HTML:
3666                 default:
3667                         hildon_picker_button_set_active (button, 1);
3668                         gtk_widget_set_sensitive (helper->align_picker, TRUE);
3669                         break;
3670                 }
3671         }
3672 }
3673
3674 static void
3675 on_align_picker_value_changed (HildonPickerButton *button,
3676                                 MessageSettingsHelper *helper)
3677 {
3678         GtkJustification new_justify;
3679         ModestMsgEditFormatState *format_state = NULL;
3680
3681         switch (hildon_picker_button_get_active (button)) {
3682         case 1:
3683                 new_justify = GTK_JUSTIFY_CENTER;
3684                 break;
3685         case 2:
3686                 new_justify = GTK_JUSTIFY_RIGHT;
3687                 break;
3688         case 0:
3689         default:
3690                 new_justify = GTK_JUSTIFY_LEFT;
3691                 break;
3692         }
3693
3694         format_state = modest_msg_edit_window_get_format_state (helper->window);
3695         if (format_state->justification != new_justify)
3696                 format_state->justification = new_justify;
3697         modest_msg_edit_window_set_format_state (helper->window, format_state);
3698         g_free (format_state);
3699 }
3700
3701 static void
3702 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3703 {
3704         GtkWidget *dialog;
3705         GtkWidget *vbox;
3706         GtkWidget *priority_hbox;
3707         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3708         GtkWidget *captioned;
3709         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3710         GtkWidget *format_picker;
3711         GtkWidget *format_selector;
3712         ModestMsgEditWindowPrivate *priv;
3713         MessageSettingsHelper helper = {0,};
3714         ModestMsgEditFormatState *format_state = NULL;
3715
3716         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3717         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3718         helper.window = window;
3719         helper.priority_group = NULL;
3720
3721         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3722         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3723
3724         dialog = gtk_dialog_new ();
3725         vbox = gtk_vbox_new (FALSE, 0);
3726         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
3727         gtk_widget_show (vbox);
3728
3729         /* Priority toggles */
3730         priority_hbox = gtk_hbox_new (TRUE, 0);
3731         high_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3732         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3733         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3734         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3735         medium_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3736         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3737         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3738         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3739         low_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3740         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3741         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3742         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3743         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, FALSE, FALSE, 0);
3744         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, FALSE, FALSE, 0);
3745         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, FALSE, FALSE, 0);
3746         gtk_widget_show_all (priority_hbox);
3747         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3748                                                          _("mcen_me_editor_message_priority"), priority_hbox);
3749         gtk_widget_show (captioned);
3750         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3751
3752         /* format selector */
3753         format_selector = hildon_touch_selector_new_text ();
3754         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_plain_text"));
3755         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_formatted_text"));
3756         format_picker = hildon_picker_button_new (MODEST_EDITABLE_SIZE,
3757                                                   HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
3758         hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (format_picker), HILDON_TOUCH_SELECTOR (format_selector));
3759         modest_maemo_utils_set_hbutton_layout (title_sizegroup, value_sizegroup,
3760                                                _("mcen_me_editor_format"), format_picker);
3761         gtk_widget_show_all (format_picker);
3762         gtk_box_pack_start (GTK_BOX (vbox), format_picker, FALSE, FALSE, 0);
3763
3764
3765         g_object_unref (title_sizegroup);
3766         g_object_unref (value_sizegroup);
3767         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_me_message_settings"));
3768
3769         /* Set current values */
3770         switch (priv->priority_flags) {
3771         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3772                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (high_toggle), TRUE);
3773                 break;
3774         case TNY_HEADER_FLAG_LOW_PRIORITY:
3775                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (low_toggle), TRUE);
3776                 break;
3777         default:
3778                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (medium_toggle), TRUE);
3779                 break;
3780         }
3781
3782         switch (modest_msg_edit_window_get_format (window)) {
3783         case MODEST_MSG_EDIT_FORMAT_TEXT:
3784                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 0);
3785                 gtk_widget_set_sensitive (helper.align_picker, FALSE);
3786                 break;
3787         case MODEST_MSG_EDIT_FORMAT_HTML:
3788         default:
3789                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 1);
3790                 gtk_widget_set_sensitive (helper.align_picker, TRUE);
3791                 break;
3792         }
3793
3794         format_state = modest_msg_edit_window_get_format_state (window);
3795         switch (format_state->justification) {
3796         case GTK_JUSTIFY_RIGHT:
3797                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 2);
3798                 break;
3799         case GTK_JUSTIFY_CENTER:
3800                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 1);
3801                 break;
3802         default:
3803                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 0);
3804                 break;
3805         
3806         }
3807         g_free (format_state);
3808
3809         /* Signal connects */
3810         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3811         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3812         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3813         g_signal_connect (G_OBJECT (format_picker), "value-changed", G_CALLBACK (on_format_picker_value_changed), &helper);
3814         g_signal_connect (G_OBJECT (helper.align_picker), "value-changed", 
3815                           G_CALLBACK (on_align_picker_value_changed), &helper);
3816         
3817         gtk_dialog_run (GTK_DIALOG (dialog));
3818         
3819         /* Read new values */
3820         
3821         gtk_widget_destroy (dialog);
3822         g_slist_free (helper.priority_group);
3823         
3824 }
3825
3826 static void on_message_settings (GtkAction *action,
3827                                  ModestMsgEditWindow *window)
3828 {
3829         modest_msg_edit_window_show_msg_settings_dialog (window);
3830 }
3831
3832 static void
3833 on_cc_button_toggled (HildonCheckButton *button,
3834                       ModestMsgEditWindow *window)
3835 {
3836         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3837
3838         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3839                                         hildon_check_button_get_active (button));
3840 }
3841
3842 static void
3843 on_bcc_button_toggled (HildonCheckButton *button,
3844                       ModestMsgEditWindow *window)
3845 {
3846         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3847
3848         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3849                                         hildon_check_button_get_active (button));
3850 }
3851
3852 static void
3853 on_find_toolbar_button_toggled (HildonCheckButton *button,
3854                                 ModestMsgEditWindow *window)
3855 {
3856         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3857         modest_msg_edit_window_toggle_find_toolbar (MODEST_MSG_EDIT_WINDOW (window),
3858                                                     hildon_check_button_get_active (button));
3859
3860 }
3861
3862 static void 
3863 setup_menu (ModestMsgEditWindow *self)
3864 {
3865         ModestMsgEditWindowPrivate *priv = NULL;
3866
3867         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3868
3869         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3870
3871         /* Settings menu buttons */
3872         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"),
3873                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3874                                            NULL);
3875         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"),
3876                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3877                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3878
3879         priv->cc_button = hildon_check_button_new (0);
3880         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3881         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3882                                         FALSE);
3883         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3884                                                   NULL);
3885         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3886                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3887         priv->bcc_button = hildon_check_button_new (0);
3888         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3889         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3890                                         FALSE);
3891         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3892                                                   NULL);
3893         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3894                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3895
3896         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"),
3897                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3898                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3899         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"),
3900                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3901                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3902         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"),
3903                                            APP_MENU_CALLBACK (on_message_settings),
3904                                            NULL);
3905         priv->find_toolbar_button = hildon_check_button_new (0);
3906         gtk_button_set_label (GTK_BUTTON (priv->find_toolbar_button), _("mcen_me_viewer_find"));
3907         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->find_toolbar_button),
3908                                         FALSE);
3909         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->find_toolbar_button),
3910                                                   NULL);
3911         g_signal_connect (G_OBJECT (priv->find_toolbar_button), "toggled",
3912                           G_CALLBACK (on_find_toolbar_button_toggled), (gpointer) self);
3913 }
3914