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