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