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