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