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