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