Avoid build problems due to the change of API in hildon
[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, const gchar *mime_type, guint64 *stream_size)
977 {
978         GdkPixbufLoader *loader;
979         GdkPixbuf *pixbuf;
980         guint64 size;
981         GError *error = NULL;
982         
983         size = 0;
984
985         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
986
987         if (loader == NULL) {
988                 if (stream_size)
989                         *stream_size = 0;
990                 return NULL;
991         }
992
993         tny_stream_reset (TNY_STREAM (stream));
994         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
995                 unsigned char read_buffer[128];
996                 gint readed;
997                 readed = tny_stream_read (TNY_STREAM (stream), (char *) read_buffer, 128);
998                 size += readed;
999                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, &error)) {
1000                         break;
1001                 }
1002         }
1003
1004         gdk_pixbuf_loader_close (loader, &error);
1005
1006         if (error)
1007                 g_error_free (error);
1008         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1009         if (pixbuf) 
1010                 g_object_ref (pixbuf);
1011         g_object_unref (loader);
1012
1013         if (!pixbuf)
1014                 return NULL;
1015
1016         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1017                 GdkPixbuf *new_pixbuf;
1018                 gint new_height;
1019                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1020                         gdk_pixbuf_get_width (pixbuf);
1021                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1022                 g_object_unref (pixbuf);
1023                 pixbuf = new_pixbuf;
1024         }
1025
1026         if (stream_size)
1027                 *stream_size = size;
1028
1029         return pixbuf;
1030 }
1031
1032 static void
1033 replace_with_images (ModestMsgEditWindow *self, TnyList *attachments)
1034 {
1035         ModestMsgEditWindowPrivate *priv;
1036         TnyIterator *iter;
1037
1038         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1039
1040         for (iter = tny_list_create_iterator (attachments);
1041              !tny_iterator_is_done (iter);
1042              tny_iterator_next (iter)) {
1043                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1044                 const gchar *cid = tny_mime_part_get_content_id (part);
1045                 const gchar *mime_type = tny_mime_part_get_content_type (part);
1046                 if ((cid != NULL)&&(mime_type != NULL)) {
1047                         guint64 stream_size;
1048                         TnyStream *stream = tny_mime_part_get_decoded_stream (part);
1049                         GdkPixbuf *pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
1050
1051
1052                         g_object_unref (stream);
1053
1054                         if (pixbuf != NULL) {
1055                                 priv->images_count ++;
1056                                 priv->images_size += stream_size;
1057                                 wp_text_buffer_replace_image (WP_TEXT_BUFFER (priv->text_buffer), cid, pixbuf);
1058                                 g_object_unref (pixbuf);
1059                         }
1060                 }
1061                 g_object_unref (part);
1062         }
1063         g_object_unref (iter);
1064 }
1065
1066 static void
1067 get_related_images (ModestMsgEditWindow *self, TnyMsg *msg)
1068 {
1069         TnyMimePart *parent = NULL;
1070         const gchar *content_type = NULL;
1071         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1072
1073         content_type = tny_mime_part_get_content_type (TNY_MIME_PART (msg));
1074         
1075         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1076                 parent = g_object_ref (msg);
1077         } else if (content_type && !g_strcasecmp (content_type, "multipart/mixed")) {
1078                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1079                 TnyIterator *iter;
1080
1081                 tny_mime_part_get_parts (TNY_MIME_PART (msg), parts);
1082                 iter = tny_list_create_iterator (parts);
1083                 while (!tny_iterator_is_done (iter)) {
1084                         TnyMimePart *part;
1085                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1086                         content_type = tny_mime_part_get_content_type (part);
1087                         if (content_type && !g_strcasecmp (content_type, "multipart/related")) {
1088                                 parent = part;
1089                                 break;
1090                         } else {
1091                                 g_object_unref (part);
1092                         }
1093                         tny_iterator_next (iter);
1094                 }
1095                 g_object_unref (iter);
1096                 g_object_unref (parts);
1097         }
1098
1099         if (parent != NULL) {
1100                 TnyList *parts = TNY_LIST (tny_simple_list_new ());
1101                 TnyIterator *iter;
1102
1103                 tny_mime_part_get_parts (TNY_MIME_PART (parent), parts);
1104                 iter = tny_list_create_iterator (parts);
1105                 while (!tny_iterator_is_done (iter)) {
1106                         TnyMimePart *part;
1107                         part = TNY_MIME_PART (tny_iterator_get_current (iter));
1108                         content_type = tny_mime_part_get_content_type (part);
1109                         if (content_type && g_str_has_prefix (content_type, "image/")) {
1110                                 tny_list_prepend (priv->images, (GObject *) part);
1111                         } 
1112                         g_object_unref (part);
1113                         tny_iterator_next (iter);
1114                 }
1115                 g_object_unref (iter);
1116                 g_object_unref (parts);
1117                 g_object_unref (parent);
1118         }
1119 }
1120
1121 static void
1122 update_next_cid (ModestMsgEditWindow *self, TnyList *attachments)
1123 {
1124         TnyIterator *iter;
1125         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1126
1127         for (iter = tny_list_create_iterator (attachments) ; 
1128              !tny_iterator_is_done (iter);
1129              tny_iterator_next (iter)) {
1130                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (iter);
1131                 const gchar *cid = tny_mime_part_get_content_id (part);
1132                 if (cid != NULL) {
1133                         char *invalid = NULL;
1134                         gint int_cid = strtol (cid, &invalid, 10);
1135                         if ((invalid != NULL) && (*invalid == '\0') && (int_cid >= priv->next_cid)) {
1136                                 priv->next_cid = int_cid + 1;
1137                         }
1138                 }
1139                 g_object_unref (part);
1140         }
1141         g_object_unref (iter);
1142 }
1143
1144 static void
1145 set_msg (ModestMsgEditWindow *self, TnyMsg *msg, gboolean preserve_is_rich)
1146 {
1147         TnyHeader *header;
1148         gchar *to, *cc, *bcc, *subject;
1149         gchar *body;
1150         ModestMsgEditWindowPrivate *priv;
1151         ModestWindowPrivate *parent_priv;
1152         GtkTextIter iter;
1153         TnyHeaderFlags priority_flags;
1154         TnyFolder *msg_folder;
1155         gboolean is_html = FALSE;
1156         gboolean field_view_set;
1157         
1158         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1159         g_return_if_fail (TNY_IS_MSG (msg));
1160
1161         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1162         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1163
1164         header = tny_msg_get_header (msg);
1165         to      = tny_header_dup_to (header);
1166         cc      = tny_header_dup_cc (header);
1167         bcc     = tny_header_dup_bcc (header);
1168         subject = tny_header_dup_subject (header);
1169         priority_flags = tny_header_get_priority (header);
1170
1171         if (to)
1172                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
1173
1174         field_view_set = TRUE;
1175         if (cc) {
1176                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
1177                 gtk_widget_set_no_show_all (priv->cc_caption, FALSE);
1178                 gtk_widget_show (priv->cc_caption);
1179         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_CC, NULL)) {
1180                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1181                 gtk_widget_hide (priv->cc_caption);
1182                 field_view_set = FALSE;
1183         }
1184         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button), field_view_set);
1185
1186         field_view_set = TRUE;
1187         if (bcc) {
1188                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
1189                 gtk_widget_set_no_show_all (priv->bcc_caption, FALSE);
1190                 gtk_widget_show (priv->bcc_caption);
1191         } else if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_BCC, NULL)) {
1192                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
1193                 gtk_widget_hide (priv->bcc_caption);
1194                 field_view_set = FALSE;
1195         }
1196         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button), field_view_set);
1197
1198
1199         if (subject)
1200                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
1201         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
1202                                                    priority_flags);
1203
1204         update_window_title (self);
1205
1206         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1207         body = modest_tny_msg_get_body (msg, TRUE, &is_html);
1208
1209         if ((body == NULL)||(body[0] == '\0')) {
1210                 g_free (body);
1211                 body = modest_text_utils_convert_to_html ("");
1212                 is_html = FALSE;
1213         }
1214         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1215         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
1216                                             (gchar *) body,
1217                                             strlen (body));
1218         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
1219         g_free (body);
1220
1221         /* Add attachments to the view */
1222         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
1223         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1224         if (tny_list_get_length (priv->attachments) == 0) {
1225                 gtk_widget_hide (priv->attachments_caption);
1226         } else {
1227                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1228                 gtk_widget_show_all (priv->attachments_caption);
1229         }
1230         get_related_images (self, msg);
1231         update_next_cid (self, priv->attachments);
1232         update_next_cid (self, priv->images);
1233         replace_with_images (self, priv->images);
1234
1235         if (preserve_is_rich && !is_html) {
1236                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1237         /* Get the default format required from configuration */
1238         } else if (!preserve_is_rich && !modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
1239                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1240         }
1241
1242         /* Set the default focus depending on having already a To: field or not */
1243         if ((!to)||(*to == '\0')) {
1244                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
1245         } else {
1246                 gtk_widget_grab_focus (priv->msg_body);
1247         }
1248
1249         DEBUG_BUFFER (WP_TEXT_BUFFER (priv->text_buffer));
1250
1251         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1252         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
1253
1254         modest_msg_edit_window_set_modified (self, FALSE);
1255
1256         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1257         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1258         text_buffer_can_undo (priv->text_buffer, FALSE, self);
1259         text_buffer_can_redo (priv->text_buffer, FALSE, self);
1260
1261         if (priv->msg_uid) {
1262                 g_free (priv->msg_uid);
1263                 priv->msg_uid = NULL;
1264         }
1265
1266         /* we should set a reference to the incoming message if it is a draft */
1267         msg_folder = tny_msg_get_folder (msg);
1268         if (msg_folder) {               
1269                 if (modest_tny_folder_is_local_folder (msg_folder)) {
1270                         TnyFolderType type = modest_tny_folder_get_local_or_mmc_folder_type (msg_folder);
1271                         if (type == TNY_FOLDER_TYPE_INVALID)
1272                                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1273                         
1274                         if (type == TNY_FOLDER_TYPE_DRAFTS) 
1275                                 priv->draft_msg = g_object_ref(msg);
1276                         if (type == TNY_FOLDER_TYPE_OUTBOX)
1277                                 priv->outbox_msg = g_object_ref(msg);
1278                         priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1279                 }
1280                 g_object_unref (msg_folder);
1281         }
1282
1283         g_free (to);
1284         g_free (subject);
1285         g_free (cc);
1286         g_free (bcc);
1287 }
1288
1289
1290 static void
1291 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
1292 {
1293         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1294         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1295         GtkWidget *placeholder;
1296         GtkWidget *tool_item;
1297         gint insert_index;
1298         gchar size_text[5];
1299         gint size_index;
1300         gint font_index;
1301         GtkWidget *sizes_menu;
1302         GtkWidget *fonts_menu;
1303         gchar *markup;
1304
1305         /* Toolbar */
1306         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
1307         gtk_toolbar_set_show_arrow (GTK_TOOLBAR (parent_priv->toolbar), FALSE);
1308         gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
1309         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
1310
1311         /* Font color placeholder */
1312         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
1313         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1314
1315         /* font color */
1316         priv->font_color_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1317         priv->font_color_button = hildon_color_button_new ();
1318         gtk_widget_set_size_request (priv->font_color_button, -1, 48);
1319         GTK_WIDGET_UNSET_FLAGS (priv->font_color_toolitem, GTK_CAN_FOCUS);
1320         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
1321         gtk_container_add (GTK_CONTAINER (priv->font_color_toolitem), priv->font_color_button);
1322         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1323         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->font_color_toolitem), TRUE);
1324         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->font_color_toolitem), insert_index);
1325         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), 
1326                                   "notify::color", 
1327                                   G_CALLBACK (modest_msg_edit_window_color_button_change), 
1328                                   window);
1329
1330         /* Font size and face placeholder */
1331         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
1332         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1333         /* font_size */
1334         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1335         priv->size_tool_button_label = gtk_label_new (NULL);
1336         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
1337         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
1338                               size_text, "</span>", NULL);
1339         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1340         g_free (markup);
1341         hildon_helper_set_logical_font (priv->size_tool_button_label, "LargeSystemFont");
1342         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
1343         sizes_menu = gtk_menu_new ();
1344         priv->sizes_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1345         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
1346                 GtkTreeIter iter;
1347
1348                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
1349                 gtk_list_store_append (GTK_LIST_STORE (priv->sizes_model), &iter);
1350
1351                 gtk_list_store_set (GTK_LIST_STORE (priv->sizes_model), &iter, 
1352                                     0, size_text,
1353                                     -1);
1354
1355                 if (wp_font_size[size_index] == 12)
1356                         priv->current_size_index = size_index;
1357                                         
1358         }
1359
1360         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_size_clicked), window);
1361         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1362         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1363         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1364         priv->font_size_toolitem = tool_item;
1365
1366         /* font face */
1367         tool_item = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
1368         priv->font_tool_button_label = gtk_label_new (NULL);
1369         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
1370         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1371         g_free(markup);
1372         hildon_helper_set_logical_font (priv->font_tool_button_label, "LargeSystemFont");
1373         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
1374         fonts_menu = gtk_menu_new ();
1375         priv->faces_model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
1376         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
1377                 GtkTreeIter iter;
1378
1379                 gtk_list_store_append (GTK_LIST_STORE (priv->faces_model), &iter);
1380
1381                 gtk_list_store_set (GTK_LIST_STORE (priv->faces_model), &iter, 
1382                                     0, wp_get_font_name (font_index),
1383                                     -1);
1384
1385                 if (font_index == DEFAULT_FONT)
1386                         priv->current_face_index = font_index;
1387         }
1388         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (font_face_clicked), window);
1389         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
1390         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1391         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1392         priv->font_face_toolitem = tool_item;
1393
1394         /* Set expand and homogeneous for remaining items */
1395         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
1396         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1397         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1398         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1399         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1400         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1401         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1402         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
1403         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
1404
1405         /* Explicitelly show all the toolbar (a normal gtk_widget_show
1406            will not show the tool items added to the placeholders) */
1407         gtk_widget_show_all (parent_priv->toolbar);
1408
1409         /* Set the no show all *after* showing all items. We do not
1410            want the toolbar to be shown with a show all because it
1411            could go agains the gconf setting regarding showing or not
1412            the toolbar of the editor window */
1413         gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1414 }
1415
1416
1417
1418 ModestWindow*
1419 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name, gboolean preserve_is_rich)
1420 {
1421         GObject *obj;
1422         ModestWindowPrivate *parent_priv;
1423         ModestMsgEditWindowPrivate *priv;
1424         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1425         ModestDimmingRulesGroup *clipboard_rules_group = NULL;
1426         ModestWindowMgr *mgr = NULL;
1427
1428         g_return_val_if_fail (msg, NULL);
1429         g_return_val_if_fail (account_name, NULL);
1430
1431         mgr = modest_runtime_get_window_mgr ();
1432         
1433         obj = G_OBJECT (modest_window_mgr_get_msg_edit_window (mgr));
1434
1435         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
1436         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1437
1438         /* Menubar. Update the state of some toggles */
1439         priv->from_field_protos = get_transports ();
1440         modest_selector_picker_set_pair_list (MODEST_SELECTOR_PICKER (priv->from_field), priv->from_field_protos);
1441         modest_selector_picker_set_active_id (MODEST_SELECTOR_PICKER (priv->from_field), (gpointer) account_name);
1442         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1443         hildon_button_set_title (HILDON_BUTTON (priv->from_field),
1444                                  _("mail_va_from"));
1445         hildon_button_set_value (HILDON_BUTTON (priv->from_field), 
1446                                  hildon_touch_selector_get_current_text 
1447                                  (HILDON_TOUCH_SELECTOR (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (priv->from_field)))));
1448         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
1449         hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
1450
1451         /* Init window */
1452         connect_signals (MODEST_MSG_EDIT_WINDOW(obj));
1453
1454         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
1455                 
1456         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
1457
1458         priv->original_account_name = (account_name) ? g_strdup (account_name) : NULL;
1459
1460         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1461         clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
1462         /* Add common dimming rules */
1463         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1464                                               modest_msg_edit_window_toolbar_dimming_entries,
1465                                               G_N_ELEMENTS (modest_msg_edit_window_toolbar_dimming_entries),
1466                                               MODEST_WINDOW (obj));
1467         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_color_toolitem,
1468                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1469                                                     MODEST_WINDOW (obj));
1470         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_size_toolitem,
1471                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1472                                                     MODEST_WINDOW (obj));
1473         modest_dimming_rules_group_add_widget_rule (toolbar_rules_group, priv->font_face_toolitem,
1474                                                     G_CALLBACK (modest_ui_dimming_rules_on_set_style),
1475                                                     MODEST_WINDOW (obj));
1476         /* Insert dimming rules group for this window */
1477         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1478         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
1479
1480         /* Setup app menu */
1481         setup_menu (MODEST_MSG_EDIT_WINDOW (obj));
1482
1483         /* Checks the dimming rules */
1484         g_object_unref (toolbar_rules_group);
1485         g_object_unref (clipboard_rules_group);
1486         gtk_widget_hide (priv->priority_icon);
1487         gtk_widget_queue_resize (priv->subject_box);
1488         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg, preserve_is_rich);
1489
1490         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1491
1492         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1493         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1494         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1495         priv->update_caption_visibility = TRUE;
1496
1497         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1498
1499         /* Track account-removed signal, this window should be closed
1500            in the case we're creating a mail associated to the account
1501            that is deleted */
1502         priv->account_removed_handler_id = 
1503                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1504                                   "account_removed",
1505                                   G_CALLBACK(on_account_removed),
1506                                   obj);
1507
1508         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1509
1510         return (ModestWindow*) obj;
1511 }
1512
1513 static gint
1514 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1515 {
1516         GString **string_buffer = (GString **) user_data;
1517
1518         *string_buffer = g_string_append (*string_buffer, buffer);
1519    
1520         return 0;
1521 }
1522
1523 /**
1524  * @result: A new string which should be freed with g_free().
1525  */
1526 static gchar *
1527 get_formatted_data (ModestMsgEditWindow *edit_window)
1528 {
1529         ModestMsgEditWindowPrivate *priv;
1530         GString *string_buffer = g_string_new ("");
1531         
1532         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1533
1534         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1535
1536         modest_text_utils_hyperlinkify (string_buffer);
1537
1538         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1539
1540         return g_string_free (string_buffer, FALSE);
1541                                                                         
1542 }
1543
1544 MsgData * 
1545 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1546 {
1547         MsgData *data;
1548         const gchar *account_name;
1549         ModestMsgEditWindowPrivate *priv;
1550         TnyIterator *att_iter;
1551         
1552         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1553
1554         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1555                                                                         
1556         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1557         g_return_val_if_fail (account_name, NULL);
1558         
1559         
1560         /* don't free these (except from) */
1561         data = g_slice_new0 (MsgData);
1562         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1563                                                              account_name);
1564         data->account_name = g_strdup (account_name);
1565         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1566         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1567         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1568         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1569         if (priv->draft_msg) {
1570                 data->draft_msg = g_object_ref (priv->draft_msg);
1571         } else if (priv->outbox_msg) {
1572                 data->draft_msg = g_object_ref (priv->outbox_msg);
1573         } else {
1574                 data->draft_msg = NULL;
1575         }
1576
1577         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1578         GtkTextIter b, e;
1579         gtk_text_buffer_get_bounds (buf, &b, &e);
1580         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1581
1582         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1583                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1584         else
1585                 data->html_body = NULL;
1586
1587         /* deep-copy the data */
1588         att_iter = tny_list_create_iterator (priv->attachments);
1589         data->attachments = NULL;
1590         while (!tny_iterator_is_done (att_iter)) {
1591                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1592                 if (!(TNY_IS_MIME_PART(part))) {
1593                         g_warning ("strange data in attachment list");
1594                         g_object_unref (part);
1595                         tny_iterator_next (att_iter);
1596                         continue;
1597                 }
1598                 data->attachments = g_list_append (data->attachments,
1599                                                    part);
1600                 tny_iterator_next (att_iter);
1601         }
1602         g_object_unref (att_iter);
1603
1604         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1605         att_iter = tny_list_create_iterator (priv->images);
1606         data->images = NULL;
1607         while (!tny_iterator_is_done (att_iter)) {
1608                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1609                 const gchar *cid;
1610                 if (!(TNY_IS_MIME_PART(part))) {
1611                         g_warning ("strange data in attachment list");
1612                         g_object_unref (part);
1613                         tny_iterator_next (att_iter);
1614                         continue;
1615                 }
1616                 cid = tny_mime_part_get_content_id (part);
1617                 if (cid) {                      
1618                         gchar *image_tag_id;
1619                         GtkTextTag *image_tag;
1620                         GtkTextIter iter;
1621                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1622                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1623                         g_free (image_tag_id);
1624                         
1625                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1626                         if (image_tag && 
1627                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1628                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1629                                 data->images = g_list_append (data->images,
1630                                                               g_object_ref (part));
1631                 }
1632                 g_object_unref (part);
1633                 tny_iterator_next (att_iter);
1634         }
1635         g_object_unref (att_iter);
1636         
1637         data->priority_flags = priv->priority_flags;
1638
1639         return data;
1640 }
1641
1642
1643 static void
1644 unref_gobject (GObject *obj, gpointer data)
1645 {
1646         if (!G_IS_OBJECT(obj))
1647                 return;
1648         g_object_unref (obj);
1649 }
1650
1651 void 
1652 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1653                                                       MsgData *data)
1654 {
1655         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1656
1657         if (!data)
1658                 return;
1659
1660         g_free (data->to);
1661         g_free (data->cc);
1662         g_free (data->bcc);
1663         g_free (data->from);
1664         g_free (data->subject);
1665         g_free (data->plain_body);
1666         g_free (data->html_body);
1667         g_free (data->account_name);
1668         
1669         if (data->draft_msg != NULL) {
1670                 g_object_unref (data->draft_msg);
1671                 data->draft_msg = NULL;
1672         }
1673         
1674         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1675         g_list_free (data->attachments);
1676         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1677         g_list_free (data->images);
1678         
1679         g_slice_free (MsgData, data);
1680 }
1681
1682 void                    
1683 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1684                                        gint *parts_count,
1685                                        guint64 *parts_size)
1686 {
1687         ModestMsgEditWindowPrivate *priv;
1688
1689         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1690
1691         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1692
1693         /* TODO: add images */
1694         *parts_size += priv->images_size;
1695         *parts_count += priv->images_count;
1696
1697 }
1698
1699 ModestMsgEditFormat
1700 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1701 {
1702         gboolean rich_text;
1703         ModestMsgEditWindowPrivate *priv = NULL;
1704         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1705
1706         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1707
1708         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1709         if (rich_text)
1710                 return MODEST_MSG_EDIT_FORMAT_HTML;
1711         else
1712                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1713 }
1714
1715 void
1716 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1717                                    ModestMsgEditFormat format)
1718 {
1719         ModestMsgEditWindowPrivate *priv;
1720
1721         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1722         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1723
1724         switch (format) {
1725         case MODEST_MSG_EDIT_FORMAT_HTML:
1726                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1727                 break;
1728         case MODEST_MSG_EDIT_FORMAT_TEXT:
1729                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1730                 break;
1731         default:
1732                 g_return_if_reached ();
1733         }
1734 }
1735
1736 ModestMsgEditFormatState *
1737 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1738 {
1739         ModestMsgEditFormatState *format_state = NULL;
1740         ModestMsgEditWindowPrivate *priv;
1741         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1742
1743         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1744         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1745
1746         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1747
1748         format_state = g_new0 (ModestMsgEditFormatState, 1);
1749         format_state->bold = buffer_format->bold&0x1;
1750         format_state->italics = buffer_format->italic&0x1;
1751         format_state->bullet = buffer_format->bullet&0x1;
1752         format_state->color = buffer_format->color;
1753         format_state->font_size = buffer_format->font_size;
1754         format_state->font_family = wp_get_font_name (buffer_format->font);
1755         format_state->justification = buffer_format->justification;
1756         g_free (buffer_format);
1757
1758         return format_state;
1759  
1760 }
1761
1762 void
1763 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1764                                          const ModestMsgEditFormatState *format_state)
1765 {
1766         ModestMsgEditWindowPrivate *priv;
1767         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1768         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1769         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1770         g_return_if_fail (format_state != NULL);
1771
1772         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1773         gtk_widget_grab_focus (priv->msg_body);
1774         buffer_format->bold = (format_state->bold != FALSE);
1775         buffer_format->italic = (format_state->italics != FALSE);
1776         buffer_format->color = format_state->color;
1777         buffer_format->font_size = format_state->font_size;
1778         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1779         buffer_format->justification = format_state->justification;
1780         buffer_format->bullet = format_state->bullet;
1781
1782         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1783
1784         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1785         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1786         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1787         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1788         buffer_format->cs.font = (buffer_format->font != current_format->font);
1789         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1790         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1791
1792         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1793         if (buffer_format->cs.bold) {
1794                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
1795                                               GINT_TO_POINTER (buffer_format->bold&0x1));
1796         }
1797         if (buffer_format->cs.italic) {
1798                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
1799                                               GINT_TO_POINTER (buffer_format->italic&0x1));
1800         }
1801         if (buffer_format->cs.color) {
1802                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1803                                               GINT_TO_POINTER (&(buffer_format->color)));
1804         }
1805         if (buffer_format->cs.font_size) {
1806                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
1807                                               GINT_TO_POINTER (buffer_format->font_size));
1808         }
1809         if (buffer_format->cs.justification) {
1810                 switch (buffer_format->justification) {
1811                 case GTK_JUSTIFY_LEFT:
1812                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
1813                                                       GINT_TO_POINTER(TRUE));
1814                         break;
1815                 case GTK_JUSTIFY_CENTER:
1816                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
1817                                                       GINT_TO_POINTER(TRUE));
1818                         break;
1819                 case GTK_JUSTIFY_RIGHT:
1820                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
1821                                                       GINT_TO_POINTER(TRUE));
1822                         break;
1823                 default:
1824                         break;
1825                 }
1826                         
1827         }
1828         if (buffer_format->cs.font) {
1829                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
1830                                               GINT_TO_POINTER (buffer_format->font));
1831         }
1832         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1833         if (buffer_format->cs.bullet) {
1834                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
1835                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
1836         }
1837 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1838         
1839         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
1840         
1841         g_free (buffer_format);
1842         g_free (current_format);
1843
1844         /* Check dimming rules */
1845         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1846         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1847 }
1848
1849 static void
1850 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1851 {
1852         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1853         GtkAction *action;
1854         ModestWindowPrivate *parent_priv;
1855         ModestMsgEditWindowPrivate *priv;
1856         
1857         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1858         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1859
1860         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1861                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
1862                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1863                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1864         } else {
1865                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
1866                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1867                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1868         }
1869
1870         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1871
1872         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1873         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1874
1875         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1876         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1877
1878 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
1879 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
1880
1881         action = NULL;
1882         switch (buffer_format->justification)
1883         {
1884         case GTK_JUSTIFY_LEFT:
1885                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
1886                 break;
1887         case GTK_JUSTIFY_CENTER:
1888                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
1889                 break;
1890         case GTK_JUSTIFY_RIGHT:
1891                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
1892                 break;
1893         default:
1894                 break;
1895         }
1896         
1897         if (action != NULL)
1898                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1899         
1900         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1901                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1902                                          window);
1903         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1904         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1905                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1906                                            window);
1907
1908         if (priv->current_size_index != buffer_format->font_size) {
1909                 GtkTreeIter iter;
1910                 GtkTreePath *path;
1911
1912                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
1913                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
1914                         gchar *size_text;
1915                         gchar *markup;
1916
1917                         priv->current_size_index = buffer_format->font_size;
1918
1919                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
1920                         markup = g_strconcat ("<span font_family='Sans'>", 
1921                                               size_text, "</span>", NULL);
1922                         
1923                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1924                         g_free (markup);
1925                         g_free (size_text);
1926                 }
1927                 gtk_tree_path_free (path);              
1928         }
1929
1930         if (priv->current_face_index != buffer_format->font) {
1931                 GtkTreeIter iter;
1932                 GtkTreePath *path;
1933
1934                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
1935                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
1936                         gchar *face_name;
1937                         gchar *markup;
1938
1939                         priv->current_face_index = buffer_format->font;
1940                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
1941                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
1942                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1943                         g_free (face_name);
1944                         g_free (markup);
1945                 }
1946
1947         }
1948
1949         g_free (buffer_format);
1950
1951 }
1952
1953 #ifdef MODEST_HILDON_VERSION_0
1954 void
1955 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1956 {
1957         
1958         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1959         ModestMsgEditWindowPrivate *priv;
1960         GtkWidget *dialog = NULL;
1961         gint response;
1962         GdkColor *new_color = NULL;
1963
1964         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1965         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1966         
1967         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1968         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1969         g_free (buffer_format);
1970
1971         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1972                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1973                 if (new_color != NULL) {
1974                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
1975                                                       (gpointer) new_color);
1976                 }
1977         }
1978         gtk_widget_destroy (dialog);
1979 }
1980
1981
1982 void
1983 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1984 {
1985         
1986         ModestMsgEditWindowPrivate *priv;
1987         GtkWidget *dialog = NULL;
1988         gint response;
1989         GdkColor *old_color = NULL;
1990         const GdkColor *new_color = NULL;
1991         
1992         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1993         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1994         
1995         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1996         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1997
1998         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
1999                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2000                 if (new_color != NULL)
2001                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2002         }
2003         gtk_widget_destroy (dialog);
2004
2005 }
2006
2007 #else 
2008 void
2009 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2010 {
2011         
2012         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2013         ModestMsgEditWindowPrivate *priv;
2014         GtkWidget *dialog = NULL;
2015
2016         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2017         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2018                 
2019         dialog = hildon_color_chooser_new ();
2020         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2021         g_free (buffer_format);
2022
2023         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2024                 GdkColor col;
2025                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2026                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2027                                               (gpointer) &col);
2028         }
2029         gtk_widget_destroy (dialog);
2030 }
2031
2032
2033 void
2034 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2035 {
2036         
2037         ModestMsgEditWindowPrivate *priv;
2038         GtkWidget *dialog = NULL;
2039         GdkColor *old_color = NULL;
2040         
2041         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2042         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2043         
2044         dialog = hildon_color_chooser_new ();
2045         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2046
2047         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2048                 GdkColor col;
2049                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2050                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2051         }
2052         gtk_widget_destroy (dialog);
2053 }
2054
2055 #endif /*!MODEST_HILDON_VERSION_0*/
2056
2057
2058
2059 static TnyStream*
2060 create_stream_for_uri (const gchar* uri)
2061 {
2062         if (!uri)
2063                 return NULL;
2064                 
2065         TnyStream *result = NULL;
2066
2067         GnomeVFSHandle *handle = NULL;
2068         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2069         if (test == GNOME_VFS_OK) {
2070                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2071                 /* Streams over OBEX (Bluetooth) are not seekable but
2072                  * we expect them to be (we might need to read them
2073                  * several times). So if this is a Bluetooth URI just
2074                  * read the whole file into memory (this is not a fast
2075                  * protocol so we can assume that these files are not
2076                  * going to be very big) */
2077                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2078                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2079                         TnyStream *memstream = tny_camel_mem_stream_new ();
2080                         tny_stream_write_to_stream (vfssstream, memstream);
2081                         g_object_unref (vfssstream);
2082                         result = memstream;
2083                 } else {
2084                         result = vfssstream;
2085                 }
2086         }
2087         
2088         return result;
2089 }
2090
2091 void
2092 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2093 {
2094         
2095         ModestMsgEditWindowPrivate *priv;
2096         GtkWidget *dialog = NULL;
2097         gint response = 0;
2098         GSList *uris = NULL;
2099         GSList *uri_node = NULL;
2100         
2101         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2102         
2103         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2104         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2105         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2106
2107         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2108
2109         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2110                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2111
2112         response = gtk_dialog_run (GTK_DIALOG (dialog));
2113         switch (response) {
2114         case GTK_RESPONSE_OK:
2115                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2116                 break;
2117         default:
2118                 break;
2119         }
2120         gtk_widget_destroy (dialog);
2121
2122         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2123                 const gchar *uri;
2124                 GnomeVFSHandle *handle = NULL;
2125                 GnomeVFSResult result;
2126                 GtkTextIter position;
2127                 GtkTextMark *insert_mark;
2128
2129                 uri = (const gchar *) uri_node->data;
2130                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2131                 if (result == GNOME_VFS_OK) {
2132                         GdkPixbuf *pixbuf;
2133                         GnomeVFSFileInfo *info;
2134                         gchar *filename, *basename, *escaped_filename;
2135                         TnyMimePart *mime_part;
2136                         gchar *content_id;
2137                         const gchar *mime_type = NULL;
2138                         GnomeVFSURI *vfs_uri;
2139                         guint64 stream_size;
2140
2141                         gnome_vfs_close (handle);
2142                         vfs_uri = gnome_vfs_uri_new (uri);
2143
2144                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2145                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2146                         g_free (escaped_filename);
2147                         gnome_vfs_uri_unref (vfs_uri);
2148                         info = gnome_vfs_file_info_new ();
2149
2150                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2151                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2152                             == GNOME_VFS_OK)
2153                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2154
2155                         mime_part = tny_platform_factory_new_mime_part
2156                                 (modest_runtime_get_platform_factory ());
2157
2158                         TnyStream *stream = create_stream_for_uri (uri);
2159
2160                         if (stream == NULL) {
2161
2162                                 modest_platform_information_banner (NULL, NULL, 
2163                                                                     _FM("sfil_ib_opening_not_allowed"));
2164
2165                                 g_object_unref (mime_part);
2166                                 gnome_vfs_file_info_unref (info);
2167                                 continue;
2168                         }
2169
2170                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2171
2172                         content_id = g_strdup_printf ("%d", priv->next_cid);
2173                         tny_mime_part_set_content_id (mime_part, content_id);
2174                         g_free (content_id);
2175                         priv->next_cid++;
2176
2177                         basename = g_path_get_basename (filename);
2178                         tny_mime_part_set_filename (mime_part, basename);
2179                         g_free (basename);
2180
2181                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size);
2182
2183                         if (pixbuf != NULL) {
2184                                 priv->images_size += stream_size;
2185                                 priv->images_count ++;
2186                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2187                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2188                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
2189                                 g_object_unref (pixbuf);
2190
2191                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2192                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2193                         } else {
2194                                 modest_platform_information_banner (NULL, NULL,
2195                                                                     _("mail_ib_file_operation_failed"));
2196                         }
2197
2198                         g_free (filename);
2199                         g_object_unref (mime_part);
2200                         gnome_vfs_file_info_unref (info);
2201
2202                 }
2203         }
2204
2205
2206 }
2207
2208 static void
2209 on_attach_file_response (GtkDialog *dialog,
2210                          gint       arg1,
2211                          gpointer   user_data)
2212 {
2213         GSList *uris = NULL;
2214         GSList *uri_node;
2215         GnomeVFSFileSize total_size, allowed_size;
2216         ModestMsgEditWindow *window;
2217         ModestMsgEditWindowPrivate *priv;
2218         gint att_num;
2219         guint64 att_size;
2220
2221         switch (arg1) {
2222         case GTK_RESPONSE_OK:
2223                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2224                 break;
2225         default:
2226                 break;
2227         }
2228
2229         window = MODEST_MSG_EDIT_WINDOW (user_data);
2230         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2231
2232         /* allowed size is the maximum size - what's already there */
2233         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2234                                            &att_num, &att_size);
2235         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2236
2237         total_size = 0;
2238         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2239
2240                 const gchar *uri = (const gchar *) uri_node->data;
2241
2242                 total_size += 
2243                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2244
2245                 if (total_size > allowed_size) {
2246                         g_warning ("%s: total size: %u", 
2247                                    __FUNCTION__, (unsigned int)total_size);
2248                         break;
2249                 }
2250                 allowed_size -= total_size;
2251         }
2252         g_slist_foreach (uris, (GFunc) g_free, NULL);
2253         g_slist_free (uris);
2254
2255         gtk_widget_destroy (GTK_WIDGET (dialog));
2256 }
2257
2258 void
2259 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2260 {
2261         GtkWidget *dialog = NULL;
2262         ModestMsgEditWindowPrivate *priv;
2263
2264         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2265
2266         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2267
2268         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2269                 return;
2270
2271         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2272                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2273         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2274         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2275         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2276                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2277
2278         /* Connect to response & show */
2279         g_signal_connect (dialog, "response", 
2280                           G_CALLBACK (on_attach_file_response), window);
2281         gtk_widget_show (dialog);
2282 }
2283
2284
2285 GnomeVFSFileSize
2286 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2287                                         const gchar *uri, 
2288                                         GnomeVFSFileSize allowed_size)
2289
2290 {
2291         GnomeVFSHandle *handle = NULL;
2292         ModestMsgEditWindowPrivate *priv;
2293         GnomeVFSResult result;
2294         GnomeVFSFileSize size = 0;
2295         g_return_val_if_fail (window, 0);
2296         g_return_val_if_fail (uri, 0);
2297
2298         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2299
2300         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2301         if (result == GNOME_VFS_OK) {
2302                 TnyMimePart *mime_part;
2303                 TnyStream *stream;
2304                 const gchar *mime_type = NULL;
2305                 gchar *basename;
2306                 gchar *escaped_filename;
2307                 gchar *filename;
2308                 gchar *content_id;
2309                 GnomeVFSFileInfo *info;
2310                 GnomeVFSURI *vfs_uri;
2311
2312                 gnome_vfs_close (handle);
2313                 vfs_uri = gnome_vfs_uri_new (uri);
2314                 
2315
2316                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2317                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2318                 g_free (escaped_filename);
2319                 gnome_vfs_uri_unref (vfs_uri);
2320
2321                 info = gnome_vfs_file_info_new ();
2322                 
2323                 if (gnome_vfs_get_file_info (uri, 
2324                                              info, 
2325                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2326                     == GNOME_VFS_OK)
2327                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2328                 mime_part = tny_platform_factory_new_mime_part
2329                         (modest_runtime_get_platform_factory ());
2330                 
2331                 /* try to get the attachment's size; this may fail for weird
2332                  * file systems, like obex, upnp... */
2333                 if (allowed_size != 0 &&
2334                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2335                         size = info->size;
2336                         if (size > allowed_size) {
2337                                 modest_platform_information_banner (NULL, NULL, 
2338                                                                     _FM("sfil_ib_opening_not_allowed"));
2339                                 return 0;
2340                         }
2341                 } else
2342                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2343                 
2344                 stream = create_stream_for_uri (uri);
2345                 
2346                 if (stream == NULL) {
2347
2348                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2349
2350                         g_object_unref (mime_part);
2351                         gnome_vfs_file_info_unref (info);
2352                         return 0;
2353                 }
2354
2355                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2356                 g_object_unref (stream);
2357                 
2358                 content_id = g_strdup_printf ("%d", priv->next_cid);
2359                 tny_mime_part_set_content_id (mime_part, content_id);
2360                 g_free (content_id);
2361                 priv->next_cid++;
2362                 
2363                 basename = g_path_get_basename (filename);
2364                 tny_mime_part_set_filename (mime_part, basename);
2365                 g_free (basename);
2366                 
2367                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2368                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2369                                                         mime_part,
2370                                                         info->size == 0, info->size);
2371                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2372                 gtk_widget_show_all (priv->attachments_caption);
2373                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2374                 g_free (filename);
2375                 g_object_unref (mime_part);
2376                 gnome_vfs_file_info_unref (info);
2377         }
2378
2379         return size;
2380 }
2381
2382 void
2383 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2384                                            TnyList *att_list)
2385 {
2386         ModestMsgEditWindowPrivate *priv;
2387         TnyIterator *iter;
2388
2389         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2390         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2391
2392         if (att_list == NULL) {
2393                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2394                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2395                         g_object_unref (att_list);
2396                         return;
2397                 }
2398                 
2399         } else {
2400                 g_object_ref (att_list);
2401         }
2402
2403         if (tny_list_get_length (att_list) == 0) {
2404                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2405         } else {
2406                 gboolean dialog_response;
2407                 gchar *message = NULL;
2408                 gchar *filename = NULL;
2409
2410                 if (tny_list_get_length (att_list) == 1) {
2411                         TnyMimePart *part;
2412                         iter = tny_list_create_iterator (att_list);
2413                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2414                         g_object_unref (iter);
2415                         if (TNY_IS_MSG (part)) {
2416                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2417                                 if (header) {
2418                                         filename = tny_header_dup_subject (header);
2419                                         g_object_unref (header);
2420                                 }
2421                                 if (filename == NULL) {
2422                                         filename = g_strdup (_("mail_va_no_subject"));
2423                                 }
2424                         } else {
2425                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2426                         }
2427                         g_object_unref (part);
2428                 } else {
2429                         filename = g_strdup ("");
2430                 }
2431                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2432                                                     "emev_nc_delete_attachments",
2433                                                     tny_list_get_length (att_list)), filename);
2434                 g_free (filename);
2435
2436                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2437                                                                            message);
2438                 g_free (message);
2439
2440                 if (dialog_response != GTK_RESPONSE_OK) {
2441                         g_object_unref (att_list);
2442                         return;
2443                 }
2444
2445                 for (iter = tny_list_create_iterator (att_list);
2446                      !tny_iterator_is_done (iter);
2447                      tny_iterator_next (iter)) {
2448                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2449                         const gchar *att_id;
2450                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2451
2452                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2453                                                                    mime_part);
2454                         if (tny_list_get_length (priv->attachments) == 0)
2455                                 gtk_widget_hide (priv->attachments_caption);
2456                         att_id = tny_mime_part_get_content_id (mime_part);
2457                         if (att_id != NULL)
2458                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2459                                                                  att_id);
2460                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2461                         g_object_unref (mime_part);
2462                 }
2463                 g_object_unref (iter);
2464         }
2465
2466         g_object_unref (att_list);
2467
2468         /* if the last attachment has been removed, focus the Subject: field */
2469         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2470                 gtk_widget_grab_focus (priv->subject_field);
2471 }
2472
2473 static void
2474 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2475                                             gpointer userdata)
2476 {
2477         ModestMsgEditWindowPrivate *priv;
2478         GdkColor *new_color;
2479         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2480         
2481 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2482         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2483 #else 
2484         GdkColor col;
2485         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2486         new_color = &col;
2487 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2488
2489         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2490         
2491         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2492
2493 }
2494
2495 static void
2496 font_size_clicked (GtkToolButton *button,
2497                    ModestMsgEditWindow *window)
2498 {
2499         ModestMsgEditWindowPrivate *priv;
2500         GtkWidget *selector, *dialog;
2501         
2502         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2503
2504         selector = hildon_touch_selector_new ();
2505         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2506         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2507
2508         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2509         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2510
2511         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2512                 gint new_index;
2513                 gchar *size_text;
2514                 gchar *markup;
2515                 WPTextBufferFormat format;
2516
2517                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2518
2519                 memset (&format, 0, sizeof (format));
2520                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2521
2522                 format.cs.font_size = TRUE;
2523                 format.cs.text_position = TRUE;
2524                 format.cs.font = TRUE;
2525                 format.font_size = new_index;
2526 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2527
2528                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2529                                                    GINT_TO_POINTER (new_index)))
2530                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2531                 
2532                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2533                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2534                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2535                                       size_text, "</span>", NULL);
2536                 g_free (size_text);
2537                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2538                 g_free (markup);
2539
2540         }
2541         gtk_widget_destroy (dialog);
2542
2543         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2544
2545 }
2546
2547 static void
2548 font_face_clicked (GtkToolButton *button,
2549                    ModestMsgEditWindow *window)
2550 {
2551         ModestMsgEditWindowPrivate *priv;
2552         GtkWidget *selector, *dialog;
2553         GtkCellRenderer *renderer;
2554         
2555         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2556
2557         selector = hildon_touch_selector_new ();
2558         renderer = gtk_cell_renderer_text_new ();
2559         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2560                                              renderer, "family", 0, "text", 0, NULL);
2561         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2562
2563         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2564         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2565
2566         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2567                 gint new_font_index;
2568                 GtkTreePath *path;
2569                 GtkTreeIter iter;
2570
2571                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2572                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2573                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2574                         gchar *face_name;
2575                         gchar *markup;
2576
2577                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2578
2579                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2580                                                            GINT_TO_POINTER(new_font_index)))
2581                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2582
2583                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2584                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2585
2586                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2587                         g_free (face_name);
2588                         g_free (markup);
2589                 }
2590                 gtk_tree_path_free (path);
2591
2592         }
2593         gtk_widget_destroy (dialog);
2594
2595         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2596
2597 }
2598
2599 void
2600 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2601                                 gboolean show)
2602 {
2603         ModestMsgEditWindowPrivate *priv = NULL;
2604         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2605
2606         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2607         if (!priv->update_caption_visibility)
2608                 return;
2609
2610         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2611         if (show)
2612                 gtk_widget_show (priv->cc_caption);
2613         else
2614                 gtk_widget_hide (priv->cc_caption);
2615
2616         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2617 }
2618
2619 void
2620 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2621                                  gboolean show)
2622 {
2623         ModestMsgEditWindowPrivate *priv = NULL;
2624         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2625
2626         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2627         if (!priv->update_caption_visibility)
2628                 return;
2629
2630         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2631         if (show)
2632                 gtk_widget_show (priv->bcc_caption);
2633         else
2634                 gtk_widget_hide (priv->bcc_caption);
2635
2636         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2637 }
2638
2639 static void
2640 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2641                                          ModestRecptEditor *editor)
2642 {
2643         ModestMsgEditWindowPrivate *priv;
2644
2645         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2646         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2647         
2648         /* we check for low-mem; in that case, show a warning, and don't allow
2649          * for the addressbook
2650          */
2651         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2652                 return;
2653
2654         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2655
2656         if (editor == NULL) {
2657                 GtkWidget *view_focus;
2658                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2659
2660                 /* This code should be kept in sync with ModestRecptEditor. The
2661                    textview inside the recpt editor is the one that really gets the
2662                    focus. As it's inside a scrolled window, and this one inside the
2663                    hbox recpt editor inherits from, we'll need to go up in the 
2664                    hierarchy to know if the text view is part of the recpt editor
2665                    or if it's a different text entry */
2666
2667                 if (gtk_widget_get_parent (view_focus)) {
2668                         GtkWidget *first_parent;
2669
2670                         first_parent = gtk_widget_get_parent (view_focus);
2671                         if (gtk_widget_get_parent (first_parent) && 
2672                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2673                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2674                         }
2675                 }
2676
2677                 if (editor == NULL)
2678                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2679
2680         }
2681
2682         modest_address_book_select_addresses (editor);
2683
2684 }
2685
2686 void
2687 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2688 {
2689         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2690
2691         modest_msg_edit_window_open_addressbook (window, NULL);
2692 }
2693
2694 static void
2695 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2696                                      gboolean show_toolbar)
2697 {
2698         ModestWindowPrivate *parent_priv;
2699
2700         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2701         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2702
2703         /* We can not just use the code of
2704            modest_msg_edit_window_setup_toolbar because it has a
2705            mixture of both initialization and creation code. */
2706         if (show_toolbar)
2707                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2708         else
2709                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2710 }
2711
2712 void
2713 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2714                                            TnyHeaderFlags priority_flags)
2715 {
2716         ModestMsgEditWindowPrivate *priv;
2717         ModestWindowPrivate *parent_priv;
2718
2719         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2720
2721         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2722         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2723
2724         if (priv->priority_flags != priority_flags) {
2725                 GtkAction *priority_action = NULL;
2726
2727                 priv->priority_flags = priority_flags;
2728
2729                 switch (priority_flags) {
2730                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2731                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2732                                                       MODEST_HEADER_ICON_HIGH, 
2733                                                       HILDON_ICON_SIZE_SMALL);
2734                         gtk_widget_show (priv->priority_icon);
2735                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2736                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2737                         break;
2738                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2739                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2740                                                       MODEST_HEADER_ICON_LOW,
2741                                                       HILDON_ICON_SIZE_SMALL);
2742                         gtk_widget_show (priv->priority_icon);
2743                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2744                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2745                         break;
2746                 default:
2747                         gtk_widget_hide (priv->priority_icon);
2748                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2749                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2750                         break;
2751                 }
2752                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2753                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2754         }
2755         gtk_widget_queue_resize (priv->subject_box);
2756 }
2757
2758 void
2759 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2760                                         gint file_format)
2761 {
2762         ModestMsgEditWindowPrivate *priv;
2763         ModestWindowPrivate *parent_priv;
2764         gint current_format;
2765
2766         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2767
2768         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2769         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2770
2771         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2772                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2773
2774         if (current_format != file_format) {
2775                 switch (file_format) {
2776                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2777                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2778                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2779                         break;
2780                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2781                 {
2782                         GtkWidget *dialog;
2783                         gint response;
2784                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2785                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2786                         gtk_widget_destroy (dialog);
2787                         if (response == GTK_RESPONSE_OK) {
2788                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2789                         } else {
2790                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2791                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2792                         }
2793                 }
2794                         break;
2795                 }
2796                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2797                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2798                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2799         }
2800 }
2801
2802 void
2803 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2804 {
2805         GtkWidget *dialog;
2806         ModestMsgEditWindowPrivate *priv;
2807         WPTextBufferFormat oldfmt, fmt;
2808         gint old_position = 0;
2809         gint response = 0;
2810         gint position = 0;
2811         gint font_size;
2812         GdkColor *color = NULL;
2813         gboolean bold, bold_set, italic, italic_set;
2814         gboolean underline, underline_set;
2815         gboolean strikethrough, strikethrough_set;
2816         gboolean position_set;
2817         gboolean font_size_set, font_set, color_set;
2818         gchar *font_name;
2819
2820         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2821         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2822         
2823         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2824         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2825                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2826
2827         /* First we get the currently selected font information */
2828         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2829
2830         switch (oldfmt.text_position) {
2831         case TEXT_POSITION_NORMAL:
2832                 old_position = 0;
2833                 break;
2834         case TEXT_POSITION_SUPERSCRIPT:
2835                 old_position = 1;
2836                 break;
2837         default:
2838                 old_position = -1;
2839                 break;
2840         }
2841
2842         g_object_set (G_OBJECT (dialog),
2843                       "bold", oldfmt.bold != FALSE,
2844                       "bold-set", !oldfmt.cs.bold,
2845                       "underline", oldfmt.underline != FALSE,
2846                       "underline-set", !oldfmt.cs.underline,
2847                       "italic", oldfmt.italic != FALSE,
2848                       "italic-set", !oldfmt.cs.italic,
2849                       "strikethrough", oldfmt.strikethrough != FALSE,
2850                       "strikethrough-set", !oldfmt.cs.strikethrough,
2851                       "color", &oldfmt.color,
2852                       "color-set", !oldfmt.cs.color,
2853                       "size", wp_font_size[oldfmt.font_size],
2854                       "size-set", !oldfmt.cs.font_size,
2855                       "position", old_position,
2856                       "position-set", !oldfmt.cs.text_position,
2857                       "family", wp_get_font_name (oldfmt.font),
2858                       "family-set", !oldfmt.cs.font,
2859                       NULL);
2860
2861         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2862                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2863         gtk_widget_show_all (dialog);
2864         priv->font_dialog = dialog;
2865         response = gtk_dialog_run (GTK_DIALOG (dialog));
2866         priv->font_dialog = NULL;
2867         if (response == GTK_RESPONSE_OK) {
2868
2869                 g_object_get( dialog,
2870                               "bold", &bold,
2871                               "bold-set", &bold_set,
2872                               "underline", &underline,
2873                               "underline-set", &underline_set,
2874                               "italic", &italic,
2875                               "italic-set", &italic_set,
2876                               "strikethrough", &strikethrough,
2877                               "strikethrough-set", &strikethrough_set,
2878                               "color", &color,
2879                               "color-set", &color_set,
2880                               "size", &font_size,
2881                               "size-set", &font_size_set,
2882                               "family", &font_name,
2883                               "family-set", &font_set,
2884                               "position", &position,
2885                               "position-set", &position_set,
2886                               NULL );
2887                 
2888         }       
2889
2890         if (response == GTK_RESPONSE_OK) {
2891                 memset(&fmt, 0, sizeof(fmt));
2892                 if (bold_set) {
2893                         fmt.bold = bold;
2894                         fmt.cs.bold = TRUE;
2895                 }
2896                 if (italic_set) {
2897                         fmt.italic = italic;
2898                         fmt.cs.italic = TRUE;
2899                 }
2900                 if (underline_set) {
2901                         fmt.underline = underline;
2902                         fmt.cs.underline = TRUE;
2903                 }
2904                 if (strikethrough_set) {
2905                         fmt.strikethrough = strikethrough;
2906                         fmt.cs.strikethrough = TRUE;
2907                 }
2908                 if (position_set) {
2909                         fmt.text_position =
2910                                 ( position == 0 )
2911                                 ? TEXT_POSITION_NORMAL
2912                                 : ( ( position == 1 )
2913                                     ? TEXT_POSITION_SUPERSCRIPT
2914                                     : TEXT_POSITION_SUBSCRIPT );
2915                         fmt.cs.text_position = TRUE;
2916                         fmt.font_size = oldfmt.font_size;
2917                 }
2918                 if (color_set) {
2919                         fmt.color = *color;
2920                         fmt.cs.color = TRUE;
2921                 }
2922                 if (font_set) {
2923                         fmt.font = wp_get_font_index(font_name,
2924                                                      DEFAULT_FONT);
2925                         fmt.cs.font = TRUE;
2926                 }
2927                 g_free(font_name);
2928                 if (font_size_set) {
2929                         fmt.cs.font_size = TRUE;
2930                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2931                 }
2932                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2933                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2934         }
2935         gtk_widget_destroy (dialog);
2936         
2937         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2938 }
2939
2940 void
2941 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2942 {
2943         ModestMsgEditWindowPrivate *priv;
2944
2945         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2946         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2947         
2948         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2949
2950         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2951         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2952 }
2953
2954 void
2955 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2956 {
2957         ModestMsgEditWindowPrivate *priv;
2958
2959         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2960         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2961         
2962         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2963
2964         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2965         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2966
2967 }
2968
2969 static void  
2970 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2971 {
2972         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2973
2974         priv->can_undo = can_undo;
2975 }
2976
2977 static void  
2978 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2979 {
2980         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2981
2982         priv->can_redo = can_redo;
2983 }
2984
2985 gboolean            
2986 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2987 {
2988         ModestMsgEditWindowPrivate *priv;
2989         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2990         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2991
2992         return priv->can_undo;
2993 }
2994
2995 gboolean            
2996 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2997 {
2998         ModestMsgEditWindowPrivate *priv;
2999         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3000         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3001
3002         return priv->can_redo;
3003 }
3004
3005
3006 static void
3007 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3008 {
3009         GtkTextIter iter;
3010         GtkTextIter match_start, match_end;
3011
3012         if (image_id == NULL)
3013                 return;
3014
3015         gtk_text_buffer_get_start_iter (buffer, &iter);
3016
3017         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3018                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3019                 GSList *node;
3020                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3021                         GtkTextTag *tag = (GtkTextTag *) node->data;
3022                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3023                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3024                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3025                                         gint offset;
3026                                         offset = gtk_text_iter_get_offset (&match_start);
3027                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3028                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3029                                 }
3030                         }
3031                 }
3032                 gtk_text_iter_forward_char (&iter);
3033         }
3034 }
3035
3036 gboolean
3037 message_is_empty (ModestMsgEditWindow *window)
3038 {
3039         ModestMsgEditWindowPrivate *priv = NULL;
3040
3041         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3042         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3043
3044         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3045          * so we can ignore markup.
3046          */
3047         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3048         gint count = 0;
3049         if (buf)
3050                 count = gtk_text_buffer_get_char_count (buf);
3051
3052         return count == 0;
3053 }
3054
3055 static gboolean
3056 msg_body_focus (GtkWidget *focus,
3057                 GdkEventFocus *event,
3058                 gpointer userdata)
3059 {
3060         
3061         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3062         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3063         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3064         return FALSE;
3065 }
3066
3067 static void
3068 recpt_field_changed (GtkTextBuffer *buffer,
3069                   ModestMsgEditWindow *editor)
3070 {
3071         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3072         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3073 }
3074
3075 static void
3076 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3077 {
3078         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3079         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3080 }
3081
3082 void
3083 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3084                                      gboolean modified)
3085 {
3086         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3087         GtkTextBuffer *buffer;
3088
3089         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3090         gtk_text_buffer_set_modified (buffer, modified);
3091         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3092         gtk_text_buffer_set_modified (buffer, modified);
3093         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3094         gtk_text_buffer_set_modified (buffer, modified);
3095         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3096 }
3097
3098 gboolean
3099 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3100 {
3101         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3102         const char *account_name;
3103         GtkTextBuffer *buffer;
3104
3105         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3106         if (gtk_text_buffer_get_modified (buffer))
3107                 return TRUE;
3108         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3109         if (gtk_text_buffer_get_modified (buffer))
3110                 return TRUE;
3111         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3112         if (gtk_text_buffer_get_modified (buffer))
3113                 return TRUE;
3114         if (gtk_text_buffer_get_modified (priv->text_buffer))
3115                 return TRUE;
3116         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3117         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3118                 return TRUE;
3119         }
3120
3121         return FALSE;
3122 }
3123
3124
3125
3126
3127 gboolean
3128 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3129 {
3130         ModestMsgEditWindowPrivate *priv = NULL;
3131         
3132         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3133         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3134
3135         /* check if there's no recipient added */
3136         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3137             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3138             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3139                 /* no recipient contents, then select contacts */
3140                 modest_msg_edit_window_open_addressbook (window, NULL);
3141                 return FALSE;
3142         }
3143
3144         g_object_ref (window);
3145         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3146                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3147                 g_object_unref (window);
3148                 return FALSE;
3149         }
3150         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3151                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3152                 g_object_unref (window);
3153                 return FALSE;
3154         }
3155         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3156                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3157                 g_object_unref (window);
3158                 return FALSE;
3159         }
3160
3161         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3162             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3163                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3164         g_object_unref (window);
3165
3166         return TRUE;
3167
3168 }
3169
3170 static void
3171 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3172                                                ModestMsgEditWindow *window)
3173 {
3174         modest_msg_edit_window_offer_attach_file (window);
3175 }
3176
3177 const gchar *
3178 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3179 {
3180         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3181
3182         return priv->clipboard_text;
3183 }
3184
3185 static void
3186 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3187                                                GdkEvent *event,
3188                                                ModestMsgEditWindow *window)
3189 {
3190         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3191         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3192         gchar *text = NULL;
3193         if (!GTK_WIDGET_VISIBLE (window))
3194                 return;
3195
3196         g_object_ref (window);
3197         text = gtk_clipboard_wait_for_text (selection_clipboard);
3198
3199         if (priv->clipboard_text != NULL) {
3200                 g_free (priv->clipboard_text);
3201         }
3202         priv->clipboard_text = text;
3203
3204         if (GTK_WIDGET_VISIBLE (window)) {
3205                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3206         }
3207         g_object_unref (window);
3208 }
3209
3210 static gboolean clipboard_owner_change_idle (gpointer userdata)
3211 {
3212         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3213         ModestMsgEditWindowPrivate *priv;
3214
3215         gdk_threads_enter ();
3216         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3217         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3218
3219         priv->clipboard_owner_idle = 0;
3220         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3221         gdk_threads_leave ();
3222
3223         return FALSE;
3224 }
3225
3226 static void
3227 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3228 {
3229         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3230         if (priv->clipboard_owner_idle == 0) {
3231                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3232         }
3233 }
3234
3235 static void 
3236 subject_field_move_cursor (GtkEntry *entry,
3237                            GtkMovementStep step,
3238                            gint a1,
3239                            gboolean a2,
3240                            gpointer window)
3241 {
3242         if (!GTK_WIDGET_VISIBLE (window))
3243                 return;
3244
3245         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3246 }
3247
3248 static void 
3249 update_window_title (ModestMsgEditWindow *window)
3250 {
3251         ModestMsgEditWindowPrivate *priv = NULL;
3252         const gchar *subject;
3253
3254         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3255         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3256         if (subject == NULL || subject[0] == '\0')
3257                 subject = _("mail_va_new_email");
3258
3259         gtk_window_set_title (GTK_WINDOW (window), subject);
3260
3261 }
3262
3263 static void  
3264 subject_field_changed (GtkEditable *editable, 
3265                        ModestMsgEditWindow *window)
3266 {
3267         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3268         update_window_title (window);
3269         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3270         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3271         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3272 }
3273
3274 static void  
3275 subject_field_insert_text (GtkEditable *editable, 
3276                            gchar *new_text,
3277                            gint new_text_length,
3278                            gint *position,
3279                            ModestMsgEditWindow *window)
3280 {
3281         GString *result = g_string_new ("");
3282         gchar *current;
3283         gint result_len = 0;
3284         const gchar *entry_text = NULL;
3285         gint old_length;
3286
3287         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3288         old_length = g_utf8_strlen (entry_text, -1);
3289
3290         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3291                 gunichar c = g_utf8_get_char_validated (current, 8);
3292                 /* Invalid unichar, stop */
3293                 if (c == -1)
3294                         break;
3295                 /* a bullet */
3296                 if (c == 0x2022)
3297                         continue;
3298                 result = g_string_append_unichar (result, c);
3299                 result_len++;
3300         }
3301
3302         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3303                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3304                 if (result_len > 0)
3305                 {
3306                         /* Prevent endless recursion */
3307                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3308                         g_signal_emit_by_name (editable, "insert-text", 
3309                                                (gpointer) result->str, (gpointer) result->len,
3310                                                (gpointer) position, (gpointer) window);
3311                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3312                 }
3313         }
3314
3315         if (result_len + old_length > 1000) {
3316                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3317                                                 _CS("ckdg_ib_maximum_characters_reached"));
3318         }
3319         g_string_free (result, TRUE);
3320 }
3321
3322 void
3323 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3324                                             gboolean show)
3325 {
3326         ModestMsgEditWindowPrivate *priv = NULL;
3327
3328         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3329         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3330
3331         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3332
3333         if (show) {
3334                 gtk_widget_show_all (priv->find_toolbar);
3335                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3336         } else {
3337                 gtk_widget_hide_all (priv->find_toolbar);
3338                 gtk_widget_grab_focus (priv->msg_body);
3339         }
3340 }
3341
3342 static gboolean 
3343 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3344                                           const gchar *str,
3345                                           GtkTextIter *match_start,
3346                                           GtkTextIter *match_end)
3347 {
3348         GtkTextIter end_iter;
3349         gchar *str_casefold;
3350         gint str_chars_n;
3351         gchar *range_text;
3352         gchar *range_casefold;
3353         gint offset;
3354         gint range_chars_n;
3355         gboolean result = FALSE;
3356
3357         if (str == NULL)
3358                 return TRUE;
3359         
3360         /* get end iter */
3361         end_iter = *iter;
3362         gtk_text_iter_forward_to_end (&end_iter);
3363
3364         str_casefold = g_utf8_casefold (str, -1);
3365         str_chars_n = strlen (str);
3366
3367         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3368         range_casefold = g_utf8_casefold (range_text, -1);
3369         range_chars_n = strlen (range_casefold);
3370
3371         if (range_chars_n < str_chars_n) {
3372                 g_free (str_casefold);
3373                 g_free (range_text);
3374                 g_free (range_casefold);
3375                 return FALSE;
3376         }
3377
3378         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3379                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3380                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3381                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3382                         result = TRUE;
3383                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3384                                                       match_start, match_end, NULL);
3385                         g_free (found_text);
3386                 }
3387                 g_free (range_subtext);
3388                 if (result)
3389                         break;
3390         }
3391         g_free (str_casefold);
3392         g_free (range_text);
3393         g_free (range_casefold);
3394
3395         return result;
3396 }
3397
3398
3399 static void 
3400 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3401                                             ModestMsgEditWindow *window)
3402 {
3403         gchar *current_search = NULL;
3404         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3405         gboolean result;
3406         GtkTextIter selection_start, selection_end;
3407         GtkTextIter match_start, match_end;
3408         gboolean continue_search = FALSE;
3409
3410         if (message_is_empty (window)) {
3411                 g_free (priv->last_search);
3412                 priv->last_search = NULL;
3413                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3414                 return;
3415         }
3416
3417         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3418         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3419                 g_free (current_search);
3420                 g_free (priv->last_search);
3421                 priv->last_search = NULL;
3422                 /* Information banner about empty search */
3423                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3424                 return;
3425         }
3426
3427         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3428                 continue_search = TRUE;
3429         } else {
3430                 g_free (priv->last_search);
3431                 priv->last_search = g_strdup (current_search);
3432         }
3433
3434         if (continue_search) {
3435                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3436                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3437                                                                    &match_start, &match_end);
3438                 if (!result)
3439                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3440         } else {
3441                 GtkTextIter buffer_start;
3442                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3443                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3444                                                                    &match_start, &match_end);
3445                 if (!result)
3446                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3447         }
3448
3449         /* Mark as selected the string found in search */
3450         if (result) {
3451                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3452                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3453                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3454         } else {
3455                 g_free (priv->last_search);
3456                 priv->last_search = NULL;
3457         }
3458         g_free (current_search);
3459 }
3460
3461 gboolean 
3462 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3463 {
3464         ModestMsgEditWindowPrivate *priv;
3465
3466         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3467         return priv->sent;
3468 }
3469
3470 void 
3471 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3472                                  gboolean sent)
3473 {
3474         ModestMsgEditWindowPrivate *priv;
3475
3476         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3477         priv->sent = sent;
3478 }
3479
3480 static void
3481 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3482                                           ModestMsgEditWindow *window)
3483 {
3484         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3485 }
3486
3487 void
3488 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3489                                   TnyMsg *draft)
3490 {
3491         ModestMsgEditWindowPrivate *priv;
3492         TnyHeader *header = NULL;
3493
3494         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3495         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3496
3497         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3498         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3499
3500         if (priv->draft_msg != NULL) {
3501                 g_object_unref (priv->draft_msg);
3502         }
3503
3504         if (draft != NULL) {
3505                 g_object_ref (draft);
3506                 header = tny_msg_get_header (draft);
3507                 if (priv->msg_uid) {
3508                         g_free (priv->msg_uid);
3509                         priv->msg_uid = NULL;
3510                 }
3511                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3512                 if (GTK_WIDGET_REALIZED (window)) {
3513                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3514                                 gtk_widget_destroy (GTK_WIDGET (window));
3515                                 return;
3516                         }
3517                 }
3518         }
3519
3520         priv->draft_msg = draft;
3521 }
3522
3523 static void  
3524 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3525                        GtkTextIter *start, GtkTextIter *end,
3526                        gpointer userdata)
3527 {
3528         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3529         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3530         gchar *tag_name;
3531
3532         if (tag == NULL) return;
3533         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3534         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3535                 replace_with_images (window, priv->images);
3536         }
3537 }
3538
3539 void                    
3540 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3541                                  TnyMimePart *part)
3542 {
3543         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3544
3545         g_return_if_fail (TNY_IS_MIME_PART (part));
3546         tny_list_prepend (priv->attachments, (GObject *) part);
3547         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3548         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3549         gtk_widget_show_all (priv->attachments_caption);
3550         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3551 }
3552
3553 const gchar*    
3554 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3555 {
3556         ModestMsgEditWindowPrivate *priv;
3557
3558         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3559         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3560
3561         return priv->msg_uid;
3562 }
3563
3564 GtkWidget *
3565 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3566                                          ModestMsgEditWindowWidgetType widget_type)
3567 {
3568         ModestMsgEditWindowPrivate *priv;
3569
3570         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3571         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3572
3573         switch (widget_type) {
3574         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3575                 return priv->msg_body;
3576                 break;
3577         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3578                 return priv->to_field;
3579                 break;
3580         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3581                 return priv->cc_field;
3582                 break;
3583         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3584                 return priv->bcc_field;
3585                 break;
3586         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3587                 return priv->subject_field;
3588                 break;
3589         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3590                 return priv->attachments_view;
3591                 break;
3592         default:
3593                 return NULL;
3594         }
3595 }
3596
3597 static void 
3598 remove_tags (WPTextBuffer *buffer)
3599 {
3600         GtkTextIter start, end;
3601
3602         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3603         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3604
3605         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3606 }
3607
3608 static void
3609 on_account_removed (TnyAccountStore *account_store, 
3610                     TnyAccount *account,
3611                     gpointer user_data)
3612 {
3613         /* Do nothing if it's a store account, because we use the
3614            transport to send the messages */
3615         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3616                 const gchar *parent_acc = NULL;
3617                 const gchar *our_acc = NULL;
3618
3619                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3620                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3621                 /* Close this window if I'm showing a message of the removed account */
3622                 if (strcmp (parent_acc, our_acc) == 0)
3623                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3624         }
3625 }
3626
3627 static void
3628 from_field_changed (HildonPickerButton *button,
3629                     ModestMsgEditWindow *self)
3630 {
3631         ModestMsgEditWindowPrivate *priv;
3632         gboolean has_old_signature, has_new_signature;
3633         GtkTextIter iter;
3634         GtkTextIter match_start, match_end;
3635         ModestAccountMgr *mgr;
3636         gchar *signature;
3637         gchar *full_signature;
3638
3639         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3640
3641         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3642         mgr = modest_runtime_get_account_mgr ();
3643         signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_old_signature);
3644         if (has_old_signature) {
3645                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3646                 if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3647                         gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3648                         iter = match_start;
3649                 } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3650                                                          &match_start, &match_end, NULL)) {
3651                         iter = match_start;
3652                 }
3653                 g_free (full_signature);
3654         }
3655         g_free (signature);
3656
3657         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3658         signature = modest_account_mgr_get_signature (mgr, priv->last_from_account, &has_new_signature);
3659         if (has_new_signature) {
3660                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3661                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3662                 g_free (full_signature);
3663         }
3664         g_free (signature);
3665 }
3666
3667 typedef struct _MessageSettingsHelper {
3668         ModestMsgEditWindow *window;
3669         GSList *priority_group;
3670         GSList *format_group;
3671         GtkToggleButton *current_priority;
3672         GtkToggleButton *current_format;
3673 } MessageSettingsHelper;
3674
3675 static void
3676 on_priority_toggle (GtkToggleButton *button, 
3677                     MessageSettingsHelper *helper)
3678 {
3679         GSList *node;
3680         ModestMsgEditWindowPrivate *priv;
3681
3682         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3683         if (gtk_toggle_button_get_active (button)) {
3684
3685                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3686                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3687                         if ((node_button != button) &&
3688                             gtk_toggle_button_get_active (node_button)) {
3689                                 gtk_toggle_button_set_active (node_button, FALSE);
3690                         }
3691                 }
3692                 helper->current_priority = button;
3693         } else {
3694                 gboolean found = FALSE;
3695                 /* If no one is active, activate it again */
3696                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3697                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3698                         if (gtk_toggle_button_get_active (node_button)) {
3699                                 found = TRUE;
3700                                 break;
3701                         }
3702                 }
3703                 if (!found) {
3704                         gtk_toggle_button_set_active (button, TRUE);
3705                 }
3706         }
3707 }
3708
3709 static void
3710 on_format_toggle (GtkToggleButton *button,
3711                   MessageSettingsHelper *helper)
3712 {
3713         GSList *node;
3714         ModestMsgEditWindowPrivate *priv;
3715
3716         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3717         if (gtk_toggle_button_get_active (button)) {
3718
3719                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3720                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3721                         if ((node_button != button) &&
3722                             gtk_toggle_button_get_active (node_button)) {
3723                                 gtk_toggle_button_set_active (node_button, FALSE);
3724                         }
3725                 }
3726                 helper->current_format = button;
3727         } else {
3728                 gboolean found = FALSE;
3729                 /* If no one is active, activate it again */
3730                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
3731                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
3732                         if (gtk_toggle_button_get_active (node_button)) {
3733                                 found = TRUE;
3734                                 break;
3735                         }
3736                 }
3737                 if (!found) {
3738                         gtk_toggle_button_set_active (button, TRUE);
3739                 }
3740         }
3741
3742 }
3743
3744 static void
3745 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3746 {
3747         GtkWidget *dialog;
3748         GtkWidget *align;
3749         GtkWidget *vbox;
3750         GtkWidget *priority_hbox;
3751         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3752         GtkWidget *captioned;
3753         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3754         GtkWidget *format_hbox;
3755         GtkWidget *html_toggle, *text_toggle;
3756         ModestMsgEditWindowPrivate *priv;
3757         MessageSettingsHelper helper = {0,};
3758
3759         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3760         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3761         helper.window = window;
3762         helper.priority_group = NULL;
3763         helper.format_group = NULL;
3764
3765         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3766         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3767
3768         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
3769                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3770                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
3771         vbox = gtk_vbox_new (FALSE, 0);
3772         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
3773         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
3774         gtk_container_add (GTK_CONTAINER (align), vbox);
3775         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
3776         gtk_widget_show (align);
3777         gtk_widget_show (vbox);
3778
3779         /* Priority toggles */
3780         priority_hbox = gtk_hbox_new (TRUE, 0);
3781         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3782         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3783         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3784         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3785         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3786         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3787         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3788         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3789         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3790         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3791         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3792         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3793         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
3794         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
3795         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
3796         gtk_widget_show_all (priority_hbox);
3797         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3798                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
3799         gtk_widget_show (captioned);
3800         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3801
3802         /* format toggles */
3803         format_hbox = gtk_hbox_new (TRUE, 0);
3804         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3805         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
3806         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
3807         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
3808         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
3809         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
3810         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
3811         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
3812         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
3813         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
3814         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
3815         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
3816         gtk_widget_show_all (format_hbox);
3817         gtk_widget_show (format_hbox);
3818         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
3819
3820
3821         g_object_unref (title_sizegroup);
3822         g_object_unref (value_sizegroup);
3823
3824         /* Set current values */
3825         switch (priv->priority_flags) {
3826         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3827                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
3828                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
3829                 break;
3830         case TNY_HEADER_FLAG_LOW_PRIORITY:
3831                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
3832                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
3833                 break;
3834         default:
3835                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
3836                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
3837                 break;
3838         }
3839
3840         switch (modest_msg_edit_window_get_format (window)) {
3841         case MODEST_MSG_EDIT_FORMAT_TEXT:
3842                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
3843                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
3844                 break;
3845         case MODEST_MSG_EDIT_FORMAT_HTML:
3846         default:
3847                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
3848                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
3849                 break;
3850         }
3851
3852         /* Signal connects */
3853         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3854         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3855         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3856         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3857         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
3858
3859         /* Save settings if the user clicked on done */
3860         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
3861                 TnyHeaderFlags flags;
3862                 ModestMsgEditFormat old_format, new_format;
3863
3864                 /* Set priority flags */
3865                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
3866                 if (priv->priority_flags !=  flags)
3867                         modest_msg_edit_window_set_priority_flags (window, flags);
3868
3869                 /* Set edit format */
3870                 old_format = modest_msg_edit_window_get_format (window);
3871                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
3872                 if (old_format != new_format) {
3873                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
3874                         modest_msg_edit_window_set_file_format (window, file_format);
3875                 }
3876         }
3877
3878         gtk_widget_destroy (dialog);
3879         g_slist_free (helper.priority_group);
3880 }
3881
3882 static void
3883 on_message_settings (GtkAction *action,
3884                      ModestMsgEditWindow *window)
3885 {
3886         modest_msg_edit_window_show_msg_settings_dialog (window);
3887 }
3888
3889 static void
3890 on_cc_button_toggled (HildonCheckButton *button,
3891                       ModestMsgEditWindow *window)
3892 {
3893         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3894
3895         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3896                                         hildon_check_button_get_active (button));
3897 }
3898
3899 static void
3900 on_bcc_button_toggled (HildonCheckButton *button,
3901                       ModestMsgEditWindow *window)
3902 {
3903         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3904
3905         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3906                                         hildon_check_button_get_active (button));
3907 }
3908
3909 static void 
3910 setup_menu (ModestMsgEditWindow *self)
3911 {
3912         ModestMsgEditWindowPrivate *priv = NULL;
3913
3914         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3915
3916         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3917
3918         /* Settings menu buttons */
3919         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3920                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3921                                            NULL);
3922         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3923                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3924                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3925
3926         priv->cc_button = hildon_check_button_new (0);
3927         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3928         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3929                                         FALSE);
3930         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3931                                                   NULL);
3932         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3933                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3934         priv->bcc_button = hildon_check_button_new (0);
3935         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3936         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3937                                         FALSE);
3938         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3939                                                   NULL);
3940         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3941                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3942
3943         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3944                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3945                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3946         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3947                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3948                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3949         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
3950                                            APP_MENU_CALLBACK (on_message_settings),
3951                                            NULL);
3952         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
3953                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
3954                                            NULL);
3955 }
3956