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