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