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