4beebdb7ca965d570df92e4838f2f04fed4f947c
[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         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2717
2718         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), new_color);
2719
2720         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2721
2722         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2723 }
2724
2725 static void
2726 font_size_clicked (GtkToolButton *button,
2727                    ModestMsgEditWindow *window)
2728 {
2729         ModestMsgEditWindowPrivate *priv;
2730         GtkWidget *selector, *dialog;
2731         
2732         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2733
2734         selector = hildon_touch_selector_new ();
2735         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2736         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2737
2738         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2739         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2740         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2741
2742         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2743                 gint new_index;
2744                 gchar *size_text;
2745                 gchar *markup;
2746                 WPTextBufferFormat format;
2747
2748                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2749
2750                 memset (&format, 0, sizeof (format));
2751                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2752
2753                 format.cs.font_size = TRUE;
2754                 format.cs.text_position = TRUE;
2755                 format.cs.font = TRUE;
2756                 format.font_size = new_index;
2757 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2758
2759                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2760                                                    GINT_TO_POINTER (new_index)))
2761                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2762                 
2763                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2764                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2765                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2766                                       size_text, "</span>", NULL);
2767                 g_free (size_text);
2768                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2769                 g_free (markup);
2770
2771         }
2772         gtk_widget_destroy (dialog);
2773
2774         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2775
2776 }
2777
2778 static void
2779 font_face_clicked (GtkToolButton *button,
2780                    ModestMsgEditWindow *window)
2781 {
2782         ModestMsgEditWindowPrivate *priv;
2783         GtkWidget *selector, *dialog;
2784         GtkCellRenderer *renderer;
2785         
2786         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2787
2788         selector = hildon_touch_selector_new ();
2789         renderer = gtk_cell_renderer_text_new ();
2790         g_object_set (G_OBJECT (renderer), "alignment", PANGO_ALIGN_CENTER, "xalign", 0.5, NULL);
2791         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2792                                              renderer, "family", 0, "text", 0, NULL);
2793         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2794
2795         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2796         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2797         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2798
2799         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2800                 gint new_font_index;
2801                 GtkTreePath *path;
2802                 GtkTreeIter iter;
2803
2804                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2805                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2806                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2807                         gchar *face_name;
2808                         gchar *markup;
2809
2810                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2811
2812                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2813                                                            GINT_TO_POINTER(new_font_index)))
2814                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2815
2816                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2817                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2818
2819                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2820                         g_free (face_name);
2821                         g_free (markup);
2822                 }
2823                 gtk_tree_path_free (path);
2824
2825         }
2826         gtk_widget_destroy (dialog);
2827
2828         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2829
2830 }
2831
2832 void
2833 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2834                                 gboolean show)
2835 {
2836         ModestMsgEditWindowPrivate *priv = NULL;
2837         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2838
2839         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2840         if (!priv->update_caption_visibility)
2841                 return;
2842
2843         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2844         if (show)
2845                 gtk_widget_show (priv->cc_caption);
2846         else
2847                 gtk_widget_hide (priv->cc_caption);
2848
2849         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2850 }
2851
2852 void
2853 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2854                                  gboolean show)
2855 {
2856         ModestMsgEditWindowPrivate *priv = NULL;
2857         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2858
2859         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2860         if (!priv->update_caption_visibility)
2861                 return;
2862
2863         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2864         if (show)
2865                 gtk_widget_show (priv->bcc_caption);
2866         else
2867                 gtk_widget_hide (priv->bcc_caption);
2868
2869         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2870 }
2871
2872 static void
2873 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2874                                          ModestRecptEditor *editor)
2875 {
2876         ModestMsgEditWindowPrivate *priv;
2877
2878         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2879         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2880         
2881         /* we check for low-mem; in that case, show a warning, and don't allow
2882          * for the addressbook
2883          */
2884         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2885                 return;
2886
2887         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2888
2889         if (editor == NULL) {
2890                 GtkWidget *view_focus, *parent;
2891                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2892
2893                 /* This code should be kept in sync with ModestRecptEditor. The
2894                    textview inside the recpt editor is the one that really gets the
2895                    focus. As it's inside a scrolled window, and this one inside the
2896                    hbox recpt editor inherits from, we'll need to go up in the 
2897                    hierarchy to know if the text view is part of the recpt editor
2898                    or if it's a different text entry */
2899                 parent = gtk_widget_get_parent (view_focus);
2900                 if (parent && MODEST_IS_RECPT_EDITOR (parent))
2901                         editor = MODEST_RECPT_EDITOR (parent);
2902
2903                 if (editor == NULL)
2904                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2905         }
2906
2907         modest_address_book_select_addresses (editor, GTK_WINDOW (window));
2908 }
2909
2910 void
2911 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2912 {
2913         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2914
2915         modest_msg_edit_window_open_addressbook (window, NULL);
2916 }
2917
2918 static void
2919 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2920                                      gboolean show_toolbar)
2921 {
2922         ModestWindowPrivate *parent_priv;
2923         ModestMsgEditWindowPrivate *priv;
2924
2925         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2926         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
2927         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2928
2929         /* We can not just use the code of
2930            modest_msg_edit_window_setup_toolbar because it has a
2931            mixture of both initialization and creation code. */
2932         if (show_toolbar) {
2933                 gint current_format;
2934                 current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2935                         ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2936                 if (current_format == MODEST_FILE_FORMAT_PLAIN_TEXT) {
2937                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2938                 } else {
2939                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2940                 }
2941         } else {
2942                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2943         }
2944 }
2945
2946 void
2947 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2948                                            TnyHeaderFlags priority_flags)
2949 {
2950         ModestMsgEditWindowPrivate *priv;
2951         ModestWindowPrivate *parent_priv;
2952
2953         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2954
2955         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2956         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2957
2958         if (priv->priority_flags != priority_flags) {
2959                 GtkAction *priority_action = NULL;
2960
2961                 priv->priority_flags = priority_flags;
2962
2963                 switch (priority_flags) {
2964                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2965                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2966                                                       MODEST_HEADER_ICON_HIGH, 
2967                                                       HILDON_ICON_SIZE_SMALL);
2968                         gtk_widget_show (priv->priority_icon);
2969                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2970                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2971                         break;
2972                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2973                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2974                                                       MODEST_HEADER_ICON_LOW,
2975                                                       HILDON_ICON_SIZE_SMALL);
2976                         gtk_widget_show (priv->priority_icon);
2977                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2978                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2979                         break;
2980                 default:
2981                         gtk_widget_hide (priv->priority_icon);
2982                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2983                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2984                         break;
2985                 }
2986                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2987                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2988         }
2989         gtk_widget_queue_resize (priv->subject_box);
2990 }
2991
2992 void
2993 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2994                                         gint file_format)
2995 {
2996         ModestMsgEditWindowPrivate *priv;
2997         ModestWindowPrivate *parent_priv;
2998         gint current_format;
2999
3000         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3001
3002         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3003         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3004
3005         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3006                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3007
3008         gtk_widget_set_no_show_all (GTK_WIDGET (parent_priv->toolbar), TRUE);
3009
3010         if (current_format != file_format) {
3011                 switch (file_format) {
3012                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3013                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3014                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3015                         if (parent_priv->toolbar)
3016                                 gtk_widget_show (parent_priv->toolbar);
3017                         break;
3018                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3019                 {
3020                         GtkWidget *dialog;
3021                         gint response;
3022                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3023                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3024                         gtk_widget_destroy (dialog);
3025                         if (response == GTK_RESPONSE_OK) {
3026                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3027                                 if (parent_priv->toolbar)
3028                                         gtk_widget_hide (parent_priv->toolbar);
3029                         } else {
3030                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3031                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3032                         }
3033                 }
3034                         break;
3035                 }
3036                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3037                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3038                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3039         }
3040 }
3041
3042 void
3043 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3044 {
3045         GtkWidget *dialog;
3046         ModestMsgEditWindowPrivate *priv;
3047         WPTextBufferFormat oldfmt, fmt;
3048         gint old_position = 0;
3049         gint response = 0;
3050         gint position = 0;
3051         gint font_size;
3052         GdkColor *color = NULL;
3053         gboolean bold, bold_set, italic, italic_set;
3054         gboolean underline, underline_set;
3055         gboolean strikethrough, strikethrough_set;
3056         gboolean position_set;
3057         gboolean font_size_set, font_set, color_set;
3058         gchar *font_name;
3059
3060         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3061         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3062         
3063         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3064         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3065                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
3066
3067         /* First we get the currently selected font information */
3068         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3069
3070         switch (oldfmt.text_position) {
3071         case TEXT_POSITION_NORMAL:
3072                 old_position = 0;
3073                 break;
3074         case TEXT_POSITION_SUPERSCRIPT:
3075                 old_position = 1;
3076                 break;
3077         default:
3078                 old_position = -1;
3079                 break;
3080         }
3081
3082         g_object_set (G_OBJECT (dialog),
3083                       "bold", oldfmt.bold != FALSE,
3084                       "bold-set", !oldfmt.cs.bold,
3085                       "underline", oldfmt.underline != FALSE,
3086                       "underline-set", !oldfmt.cs.underline,
3087                       "italic", oldfmt.italic != FALSE,
3088                       "italic-set", !oldfmt.cs.italic,
3089                       "strikethrough", oldfmt.strikethrough != FALSE,
3090                       "strikethrough-set", !oldfmt.cs.strikethrough,
3091                       "color", &oldfmt.color,
3092                       "color-set", !oldfmt.cs.color,
3093                       "size", wp_font_size[oldfmt.font_size],
3094                       "size-set", !oldfmt.cs.font_size,
3095                       "position", old_position,
3096                       "position-set", !oldfmt.cs.text_position,
3097                       "family", wp_get_font_name (oldfmt.font),
3098                       "family-set", !oldfmt.cs.font,
3099                       NULL);
3100
3101         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
3102                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
3103         gtk_widget_show_all (dialog);
3104         priv->font_dialog = dialog;
3105         response = gtk_dialog_run (GTK_DIALOG (dialog));
3106         priv->font_dialog = NULL;
3107         if (response == GTK_RESPONSE_OK) {
3108
3109                 g_object_get( dialog,
3110                               "bold", &bold,
3111                               "bold-set", &bold_set,
3112                               "underline", &underline,
3113                               "underline-set", &underline_set,
3114                               "italic", &italic,
3115                               "italic-set", &italic_set,
3116                               "strikethrough", &strikethrough,
3117                               "strikethrough-set", &strikethrough_set,
3118                               "color", &color,
3119                               "color-set", &color_set,
3120                               "size", &font_size,
3121                               "size-set", &font_size_set,
3122                               "family", &font_name,
3123                               "family-set", &font_set,
3124                               "position", &position,
3125                               "position-set", &position_set,
3126                               NULL );
3127                 
3128         }       
3129
3130         if (response == GTK_RESPONSE_OK) {
3131                 memset(&fmt, 0, sizeof(fmt));
3132                 if (bold_set) {
3133                         fmt.bold = bold;
3134                         fmt.cs.bold = TRUE;
3135                 }
3136                 if (italic_set) {
3137                         fmt.italic = italic;
3138                         fmt.cs.italic = TRUE;
3139                 }
3140                 if (underline_set) {
3141                         fmt.underline = underline;
3142                         fmt.cs.underline = TRUE;
3143                 }
3144                 if (strikethrough_set) {
3145                         fmt.strikethrough = strikethrough;
3146                         fmt.cs.strikethrough = TRUE;
3147                 }
3148                 if (position_set) {
3149                         fmt.text_position =
3150                                 ( position == 0 )
3151                                 ? TEXT_POSITION_NORMAL
3152                                 : ( ( position == 1 )
3153                                     ? TEXT_POSITION_SUPERSCRIPT
3154                                     : TEXT_POSITION_SUBSCRIPT );
3155                         fmt.cs.text_position = TRUE;
3156                         fmt.font_size = oldfmt.font_size;
3157                 }
3158                 if (color_set) {
3159                         fmt.color = *color;
3160                         fmt.cs.color = TRUE;
3161                 }
3162                 if (font_set) {
3163                         fmt.font = wp_get_font_index(font_name,
3164                                                      DEFAULT_FONT);
3165                         fmt.cs.font = TRUE;
3166                 }
3167                 g_free(font_name);
3168                 if (font_size_set) {
3169                         fmt.cs.font_size = TRUE;
3170                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3171                 }
3172                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3173                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3174         }
3175         gtk_widget_destroy (dialog);
3176         
3177         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3178 }
3179
3180 void
3181 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3182 {
3183         ModestMsgEditWindowPrivate *priv;
3184         ModestWindowPrivate *parent_priv;
3185         gboolean was_rich_text, is_rich_text;
3186
3187         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3188         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3189         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3190
3191         was_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3192
3193         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3194
3195         is_rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
3196
3197         if (parent_priv->toolbar && was_rich_text != is_rich_text) {
3198                 if (is_rich_text)
3199                         gtk_widget_show (parent_priv->toolbar);
3200                 else
3201                         gtk_widget_hide (parent_priv->toolbar);
3202         }
3203
3204         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3205         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3206 }
3207
3208 void
3209 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3210 {
3211         ModestMsgEditWindowPrivate *priv;
3212
3213         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3214         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3215         
3216         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3217
3218         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3219         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3220
3221 }
3222
3223 static void  
3224 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3225 {
3226         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3227
3228         priv->can_undo = can_undo;
3229 }
3230
3231 static void  
3232 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3233 {
3234         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3235
3236         priv->can_redo = can_redo;
3237 }
3238
3239 gboolean            
3240 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3241 {
3242         ModestMsgEditWindowPrivate *priv;
3243         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3244         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3245
3246         return priv->can_undo;
3247 }
3248
3249 gboolean            
3250 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3251 {
3252         ModestMsgEditWindowPrivate *priv;
3253         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3254         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3255
3256         return priv->can_redo;
3257 }
3258
3259
3260 static void
3261 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3262 {
3263         GtkTextIter iter;
3264         GtkTextIter match_start, match_end;
3265
3266         if (image_id == NULL)
3267                 return;
3268
3269         gtk_text_buffer_get_start_iter (buffer, &iter);
3270
3271         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3272                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3273                 GSList *node;
3274                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3275                         GtkTextTag *tag = (GtkTextTag *) node->data;
3276                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3277                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3278                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3279                                         gint offset;
3280                                         offset = gtk_text_iter_get_offset (&match_start);
3281                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3282                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3283                                 }
3284                         }
3285                 }
3286                 gtk_text_iter_forward_char (&iter);
3287         }
3288 }
3289
3290 gboolean
3291 message_is_empty (ModestMsgEditWindow *window)
3292 {
3293         ModestMsgEditWindowPrivate *priv = NULL;
3294
3295         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3296         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3297
3298         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3299          * so we can ignore markup.
3300          */
3301         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3302         gint count = 0;
3303         if (buf)
3304                 count = gtk_text_buffer_get_char_count (buf);
3305
3306         return count == 0;
3307 }
3308
3309 static gboolean
3310 msg_body_focus (GtkWidget *focus,
3311                 GdkEventFocus *event,
3312                 gpointer userdata)
3313 {
3314         
3315         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3316         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3317         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3318         return FALSE;
3319 }
3320
3321 static void
3322 recpt_field_changed (GtkTextBuffer *buffer,
3323                   ModestMsgEditWindow *editor)
3324 {
3325         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3326         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3327 }
3328
3329 static void
3330 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3331 {
3332         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3333         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3334 }
3335
3336 void
3337 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3338                                      gboolean modified)
3339 {
3340         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3341         GtkTextBuffer *buffer;
3342
3343         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3344         gtk_text_buffer_set_modified (buffer, modified);
3345         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3346         gtk_text_buffer_set_modified (buffer, modified);
3347         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3348         gtk_text_buffer_set_modified (buffer, modified);
3349         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3350 }
3351
3352 gboolean
3353 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3354 {
3355         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3356         const char *account_name;
3357         GtkTextBuffer *buffer;
3358
3359         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3360         if (gtk_text_buffer_get_modified (buffer))
3361                 return TRUE;
3362         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3363         if (gtk_text_buffer_get_modified (buffer))
3364                 return TRUE;
3365         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3366         if (gtk_text_buffer_get_modified (buffer))
3367                 return TRUE;
3368         if (gtk_text_buffer_get_modified (priv->text_buffer))
3369                 return TRUE;
3370
3371         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3372         if (priv->original_mailbox) {
3373                 if (!account_name || strcmp (account_name, priv->original_mailbox))
3374                         return TRUE;
3375         } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3376                 return TRUE;
3377         }
3378
3379         return FALSE;
3380 }
3381
3382
3383
3384
3385 gboolean
3386 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3387 {
3388         ModestMsgEditWindowPrivate *priv = NULL;
3389         GSList *address_list = NULL;
3390
3391         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3392         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3393
3394         /* check if there's no recipient added */
3395         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3396             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3397             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3398                 /* no recipient contents, then select contacts */
3399                 modest_msg_edit_window_open_addressbook (window, NULL);
3400                 return FALSE;
3401         }
3402
3403         /* Check names */
3404         g_object_ref (window);
3405         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  &address_list)) {
3406                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3407                 g_object_unref (window);
3408                 return FALSE;
3409         }
3410         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  &address_list)) {
3411                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3412                 g_object_unref (window);
3413                 return FALSE;
3414         }
3415         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), &address_list)) {
3416                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3417                 g_object_unref (window);
3418                 return FALSE;
3419         }
3420
3421         /* Add contacts to address book */
3422         if (address_list)
3423                 modest_address_book_add_address_list (address_list);
3424
3425         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3426             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3427                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3428         g_object_unref (window);
3429
3430         return TRUE;
3431
3432 }
3433
3434 static void
3435 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3436                                                ModestMsgEditWindow *window)
3437 {
3438         modest_msg_edit_window_offer_attach_file (window);
3439 }
3440
3441 const gchar *
3442 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3443 {
3444         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3445
3446         return priv->clipboard_text;
3447 }
3448
3449 static void
3450 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3451                                                GdkEvent *event,
3452                                                ModestMsgEditWindow *window)
3453 {
3454         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3455         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3456         gchar *text = NULL;
3457
3458         /* It could happen that the window was already closed */
3459         if (!GTK_WIDGET_VISIBLE (window))
3460                 return;
3461
3462         g_object_ref (window);
3463         text = gtk_clipboard_wait_for_text (selection_clipboard);
3464
3465         if (priv->clipboard_text != NULL) {
3466                 g_free (priv->clipboard_text);
3467         }
3468         priv->clipboard_text = text;
3469
3470         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3471
3472         g_object_unref (window);
3473 }
3474
3475 static gboolean clipboard_owner_change_idle (gpointer userdata)
3476 {
3477         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3478         ModestMsgEditWindowPrivate *priv;
3479
3480         gdk_threads_enter ();
3481         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3482         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3483
3484         priv->clipboard_owner_idle = 0;
3485         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3486         gdk_threads_leave ();
3487
3488         return FALSE;
3489 }
3490
3491 static void
3492 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3493 {
3494         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3495         if (priv->clipboard_owner_idle == 0) {
3496                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3497                                                               clipboard_owner_change_idle, 
3498                                                               g_object_ref (window),
3499                                                               g_object_unref);
3500         }
3501 }
3502
3503 static void 
3504 subject_field_move_cursor (GtkEntry *entry,
3505                            GtkMovementStep step,
3506                            gint a1,
3507                            gboolean a2,
3508                            gpointer window)
3509 {
3510         /* It could happen that the window was already closed */
3511         if (!GTK_WIDGET_VISIBLE (window))
3512                 return;
3513
3514         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3515 }
3516
3517 static void 
3518 update_window_title (ModestMsgEditWindow *window)
3519 {
3520         ModestMsgEditWindowPrivate *priv = NULL;
3521         const gchar *subject;
3522
3523         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3524         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3525         if (subject == NULL || subject[0] == '\0')
3526                 subject = _("mail_va_new_email");
3527
3528         gtk_window_set_title (GTK_WINDOW (window), subject);
3529
3530 }
3531
3532
3533 static void  
3534 body_insert_text (GtkTextBuffer *buffer, 
3535                   GtkTextIter *location,
3536                   gchar *text,
3537                   gint len,
3538                   ModestMsgEditWindow *window)
3539 {
3540         GtkTextIter end_iter;
3541         gint offset;
3542         glong utf8_len;
3543         gint line;
3544         gchar *text_offset;
3545         gint text_lines;
3546
3547         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3548
3549         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
3550
3551         offset = gtk_text_iter_get_offset (&end_iter);
3552         line = gtk_text_iter_get_line (&end_iter);
3553
3554         text_offset = text;
3555         text_lines = 0;
3556         while (text_offset < text + len) {
3557                 if (*text_offset == '\n')
3558                         text_lines++;
3559                 if (text_lines + line >= MAX_BODY_LINES) {
3560                         len = text_offset - text;
3561                         break;
3562                 }
3563                 text_offset++;
3564         }
3565
3566         utf8_len = g_utf8_strlen (text, len);
3567
3568         if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3569                 g_signal_stop_emission_by_name (G_OBJECT (buffer), "insert-text");
3570                 if (line <= MAX_BODY_LINES && offset < MAX_BODY_LENGTH)
3571                 {
3572                         gchar *result;
3573                         gchar *utf8_end;
3574
3575                         utf8_end = g_utf8_offset_to_pointer (text, MAX_BODY_LENGTH - offset);
3576
3577                         /* Prevent endless recursion */
3578                         result = g_strndup (text, utf8_end - text);
3579                         g_signal_handlers_block_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3580                         g_signal_emit_by_name (G_OBJECT (buffer), "insert-text", location,
3581                                                (gpointer) result, (gpointer) (utf8_end - text),
3582                                                (gpointer) window);
3583                         g_signal_handlers_unblock_by_func (G_OBJECT (buffer), G_CALLBACK (body_insert_text), window);
3584                 }
3585
3586         }
3587         if (line > MAX_BODY_LINES || offset + utf8_len > MAX_BODY_LENGTH) {
3588                 if (priv->max_chars_banner == NULL) {
3589                         priv->max_chars_banner = hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3590                                                                                  _CS("ckdg_ib_maximum_characters_reached"));
3591                         g_object_weak_ref (G_OBJECT (priv->max_chars_banner), (GWeakNotify) max_chars_banner_unref, window);
3592                 }
3593         }
3594 }
3595
3596 static void  
3597 subject_field_changed (GtkEditable *editable, 
3598                        ModestMsgEditWindow *window)
3599 {
3600         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3601         update_window_title (window);
3602         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3603         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3604         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3605 }
3606 static void  
3607 subject_field_insert_text (GtkEditable *editable, 
3608                            gchar *new_text,
3609                            gint new_text_length,
3610                            gint *position,
3611                            ModestMsgEditWindow *window)
3612 {
3613         GString *result = g_string_new ("");
3614         gchar *current;
3615         gint result_len = 0;
3616         const gchar *entry_text = NULL;
3617         gint old_length;
3618
3619         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3620         old_length = g_utf8_strlen (entry_text, -1);
3621
3622         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3623                 gunichar c = g_utf8_get_char_validated (current, 8);
3624                 /* Invalid unichar, stop */
3625                 if (c == -1)
3626                         break;
3627                 /* a bullet */
3628                 if (c == 0x2022)
3629                         continue;
3630                 result = g_string_append_unichar (result, c);
3631                 result_len++;
3632         }
3633
3634         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3635                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3636                 if (result_len > 0)
3637                 {
3638                         /* Prevent endless recursion */
3639                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3640                         g_signal_emit_by_name (editable, "insert-text", 
3641                                                (gpointer) result->str, (gpointer) result->len,
3642                                                (gpointer) position, (gpointer) window);
3643                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3644                 }
3645         }
3646
3647         if (result_len + old_length > 1000) {
3648                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3649                                                 _CS("ckdg_ib_maximum_characters_reached"));
3650         }
3651         g_string_free (result, TRUE);
3652 }
3653
3654 void
3655 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3656                                             gboolean show)
3657 {
3658         ModestMsgEditWindowPrivate *priv = NULL;
3659
3660         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3661         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3662
3663         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3664
3665         if (show) {
3666                 gtk_widget_show_all (priv->find_toolbar);
3667                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3668         } else {
3669                 gtk_widget_hide_all (priv->find_toolbar);
3670                 gtk_widget_grab_focus (priv->msg_body);
3671         }
3672 }
3673
3674 static gboolean 
3675 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3676                                           const gchar *str,
3677                                           GtkTextIter *match_start,
3678                                           GtkTextIter *match_end)
3679 {
3680         GtkTextIter end_iter;
3681         gchar *str_casefold;
3682         gint str_chars_n;
3683         gchar *range_text;
3684         gchar *range_casefold;
3685         gint offset;
3686         gint range_chars_n;
3687         gboolean result = FALSE;
3688
3689         if (str == NULL)
3690                 return TRUE;
3691         
3692         /* get end iter */
3693         end_iter = *iter;
3694         gtk_text_iter_forward_to_end (&end_iter);
3695
3696         str_casefold = g_utf8_casefold (str, -1);
3697         str_chars_n = strlen (str);
3698
3699         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3700         range_casefold = g_utf8_casefold (range_text, -1);
3701         range_chars_n = strlen (range_casefold);
3702
3703         if (range_chars_n < str_chars_n) {
3704                 g_free (str_casefold);
3705                 g_free (range_text);
3706                 g_free (range_casefold);
3707                 return FALSE;
3708         }
3709
3710         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3711                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3712                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3713                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3714                         result = TRUE;
3715                         if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3716                                                            match_start, match_end, NULL)) {
3717                                 g_debug ("Matched string with collate, but not matched in model");
3718                         }
3719                         g_free (found_text);
3720                 }
3721                 g_free (range_subtext);
3722                 if (result)
3723                         break;
3724         }
3725         g_free (str_casefold);
3726         g_free (range_text);
3727         g_free (range_casefold);
3728
3729         return result;
3730 }
3731
3732
3733 static void 
3734 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3735                                             ModestMsgEditWindow *window)
3736 {
3737         gchar *current_search = NULL;
3738         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3739         gboolean result;
3740         GtkTextIter selection_start, selection_end;
3741         GtkTextIter match_start, match_end;
3742         gboolean continue_search = FALSE;
3743
3744         if (message_is_empty (window)) {
3745                 g_free (priv->last_search);
3746                 priv->last_search = NULL;
3747                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3748                 return;
3749         }
3750
3751         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3752         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3753                 g_free (current_search);
3754                 g_free (priv->last_search);
3755                 priv->last_search = NULL;
3756                 /* Information banner about empty search */
3757                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3758                 return;
3759         }
3760
3761         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3762                 continue_search = TRUE;
3763         } else {
3764                 g_free (priv->last_search);
3765                 priv->last_search = g_strdup (current_search);
3766         }
3767
3768         if (continue_search) {
3769                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3770                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3771                                                                    &match_start, &match_end);
3772                 if (!result)
3773                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3774         } else {
3775                 GtkTextIter buffer_start;
3776                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3777                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3778                                                                    &match_start, &match_end);
3779                 if (!result)
3780                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3781         }
3782
3783         /* Mark as selected the string found in search */
3784         if (result) {
3785                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3786                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3787                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3788         } else {
3789                 g_free (priv->last_search);
3790                 priv->last_search = NULL;
3791         }
3792         g_free (current_search);
3793 }
3794
3795 gboolean 
3796 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3797 {
3798         ModestMsgEditWindowPrivate *priv;
3799
3800         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3801         return priv->sent;
3802 }
3803
3804 void 
3805 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3806                                  gboolean sent)
3807 {
3808         ModestMsgEditWindowPrivate *priv;
3809
3810         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3811         priv->sent = sent;
3812 }
3813
3814 static void
3815 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3816                                           ModestMsgEditWindow *window)
3817 {
3818         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3819 }
3820
3821 void
3822 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3823                                   TnyMsg *draft)
3824 {
3825         ModestMsgEditWindowPrivate *priv;
3826         TnyHeader *header = NULL;
3827
3828         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3829         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3830
3831         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3832
3833         if (priv->draft_msg != NULL) {
3834                 g_object_unref (priv->draft_msg);
3835         }
3836
3837         if (draft != NULL) {
3838                 g_object_ref (draft);
3839                 header = tny_msg_get_header (draft);
3840                 if (priv->msg_uid) {
3841                         g_free (priv->msg_uid);
3842                         priv->msg_uid = NULL;
3843                 }
3844                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3845         }
3846
3847         priv->draft_msg = draft;
3848 }
3849
3850 static void  
3851 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3852                        GtkTextIter *start, GtkTextIter *end,
3853                        gpointer userdata)
3854 {
3855         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3856         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3857         gchar *tag_name;
3858
3859         if (tag == NULL) return;
3860         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3861         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3862                 replace_with_images (window, priv->images);
3863         }
3864 }
3865
3866 void                    
3867 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3868                                  TnyMimePart *part)
3869 {
3870         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3871
3872         g_return_if_fail (TNY_IS_MIME_PART (part));
3873         tny_list_prepend (priv->attachments, (GObject *) part);
3874         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3875         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3876         gtk_widget_show_all (priv->attachments_caption);
3877         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3878 }
3879
3880 const gchar*    
3881 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3882 {
3883         ModestMsgEditWindowPrivate *priv;
3884
3885         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3886         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3887
3888         return priv->msg_uid;
3889 }
3890
3891 GtkWidget *
3892 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3893                                          ModestMsgEditWindowWidgetType widget_type)
3894 {
3895         ModestMsgEditWindowPrivate *priv;
3896
3897         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3898         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3899
3900         switch (widget_type) {
3901         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3902                 return priv->msg_body;
3903                 break;
3904         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3905                 return priv->to_field;
3906                 break;
3907         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3908                 return priv->cc_field;
3909                 break;
3910         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3911                 return priv->bcc_field;
3912                 break;
3913         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3914                 return priv->subject_field;
3915                 break;
3916         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3917                 return priv->attachments_view;
3918                 break;
3919         default:
3920                 return NULL;
3921         }
3922 }
3923
3924 static void 
3925 remove_tags (WPTextBuffer *buffer)
3926 {
3927         GtkTextIter start, end;
3928
3929         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3930         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3931
3932         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3933 }
3934
3935 static void
3936 on_account_removed (TnyAccountStore *account_store, 
3937                     TnyAccount *account,
3938                     gpointer user_data)
3939 {
3940         /* Do nothing if it's a store account, because we use the
3941            transport to send the messages */
3942         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3943                 const gchar *parent_acc = NULL;
3944                 const gchar *our_acc = NULL;
3945
3946                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3947                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3948                 /* Close this window if I'm showing a message of the removed account */
3949                 if (strcmp (parent_acc, our_acc) == 0)
3950                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3951         }
3952 }
3953
3954 static void
3955 update_signature (ModestMsgEditWindow *self,
3956                   const gchar *old_account,
3957                   const gchar *new_account)
3958 {
3959         ModestMsgEditWindowPrivate *priv;
3960         gboolean has_old_signature, has_new_signature;
3961         GtkTextIter iter;
3962         ModestAccountMgr *mgr;
3963         gchar *signature;
3964
3965         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3966
3967         gtk_text_buffer_begin_user_action (priv->text_buffer);
3968
3969         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3970         mgr = modest_runtime_get_account_mgr ();
3971
3972
3973         if (old_account) {
3974                 signature = modest_account_mgr_get_signature_from_recipient (mgr, old_account, &has_old_signature);
3975                 if (has_old_signature) {
3976                         GtkTextIter match_start, match_end;
3977                         /* We cannot use
3978                            MODEST_TEXT_UTILS_SIGNATURE_MARKER as it
3979                            seems that the search has some problems
3980                            with the blank space at the end */
3981                         if (gtk_text_iter_forward_search (&iter, "--",
3982                                                           GTK_TEXT_SEARCH_TEXT_ONLY,
3983                                                           &match_start, NULL, NULL)) {
3984                                 gtk_text_buffer_get_end_iter (priv->text_buffer ,&match_end);
3985                                 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3986                                 iter = match_start;
3987                         } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3988                                                                  &match_start, &match_end, NULL)) {
3989                                 iter = match_start;
3990                         }
3991                 } else {
3992                         gtk_text_buffer_get_end_iter (priv->text_buffer, &iter);
3993                 }
3994                 g_free (signature);
3995         }
3996
3997         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3998         signature = modest_account_mgr_get_signature_from_recipient (mgr, new_account, &has_new_signature);
3999         if (has_new_signature) {
4000
4001                 gchar *full_signature = g_strconcat ((gtk_text_iter_starts_line (&iter)) ? "" : "\n",
4002                                                      MODEST_TEXT_UTILS_SIGNATURE_MARKER, "\n",
4003                                                      signature, NULL);
4004                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
4005                 g_free (full_signature);
4006         }
4007         g_free (signature);
4008         gtk_text_buffer_end_user_action (priv->text_buffer);
4009 }
4010
4011 static void update_branding (ModestMsgEditWindow *self,
4012                              const gchar *new_account)
4013 {
4014         ModestMsgEditWindowPrivate *priv;
4015         ModestAccountMgr *mgr;
4016         const GdkPixbuf *new_icon = NULL;
4017         gchar *new_label = NULL;
4018         gboolean show = FALSE;
4019
4020         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4021
4022         mgr = modest_runtime_get_account_mgr ();
4023
4024         modest_account_mgr_get_branding_from_recipient (mgr, new_account, &new_label, &new_icon, MODEST_ICON_SIZE_SMALL);
4025         if (new_icon) {
4026                 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->brand_icon), (GdkPixbuf *) new_icon);
4027                 gtk_widget_show (priv->brand_icon);
4028                 show = TRUE;
4029         } else {
4030                 gtk_widget_hide (priv->brand_icon);
4031         }
4032         if (new_label) {
4033                 gtk_label_set_text (GTK_LABEL (priv->brand_label), new_label);
4034                 gtk_widget_show (priv->brand_label);
4035                 g_free (new_label);
4036                 show = TRUE;
4037         } else {
4038                 gtk_widget_hide (priv->brand_label);
4039         }
4040
4041         if (show)
4042                 gtk_widget_show (priv->brand_container);
4043         else
4044                 gtk_widget_hide (priv->brand_container);
4045 }
4046
4047 static void
4048 from_field_changed (HildonPickerButton *button,
4049                     ModestMsgEditWindow *self)
4050 {
4051         ModestMsgEditWindowPrivate *priv;
4052         gchar *old_account, *new_account;
4053
4054         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4055
4056         old_account = priv->last_from_account;
4057         new_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
4058
4059         if (!new_account) {
4060                 g_warning ("%s, could not get the new account", __FUNCTION__);
4061                 return;
4062         }
4063
4064         /* If the From is the same do nothing */
4065         if (old_account && new_account && !strcmp (old_account, new_account))
4066                 return;
4067
4068         priv->last_from_account = new_account;
4069
4070         update_signature (self, old_account, new_account);
4071         update_branding (self, new_account);
4072
4073 }
4074
4075 typedef struct _MessageSettingsHelper {
4076         ModestMsgEditWindow *window;
4077         GSList *priority_group;
4078         GSList *format_group;
4079         GtkToggleButton *current_priority;
4080         GtkToggleButton *current_format;
4081 } MessageSettingsHelper;
4082
4083 static void
4084 on_priority_toggle (GtkToggleButton *button, 
4085                     MessageSettingsHelper *helper)
4086 {
4087         GSList *node;
4088         ModestMsgEditWindowPrivate *priv;
4089
4090         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4091         if (gtk_toggle_button_get_active (button)) {
4092
4093                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4094                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4095                         if ((node_button != button) &&
4096                             gtk_toggle_button_get_active (node_button)) {
4097                                 gtk_toggle_button_set_active (node_button, FALSE);
4098                         }
4099                 }
4100                 helper->current_priority = button;
4101         } else {
4102                 gboolean found = FALSE;
4103                 /* If no one is active, activate it again */
4104                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4105                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4106                         if (gtk_toggle_button_get_active (node_button)) {
4107                                 found = TRUE;
4108                                 break;
4109                         }
4110                 }
4111                 if (!found) {
4112                         gtk_toggle_button_set_active (button, TRUE);
4113                 }
4114         }
4115 }
4116
4117 static void
4118 on_format_toggle (GtkToggleButton *button,
4119                   MessageSettingsHelper *helper)
4120 {
4121         GSList *node;
4122         ModestMsgEditWindowPrivate *priv;
4123
4124         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4125         if (gtk_toggle_button_get_active (button)) {
4126
4127                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4128                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4129                         if ((node_button != button) &&
4130                             gtk_toggle_button_get_active (node_button)) {
4131                                 gtk_toggle_button_set_active (node_button, FALSE);
4132                         }
4133                 }
4134                 helper->current_format = button;
4135         } else {
4136                 gboolean found = FALSE;
4137                 /* If no one is active, activate it again */
4138                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4139                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4140                         if (gtk_toggle_button_get_active (node_button)) {
4141                                 found = TRUE;
4142                                 break;
4143                         }
4144                 }
4145                 if (!found) {
4146                         gtk_toggle_button_set_active (button, TRUE);
4147                 }
4148         }
4149
4150 }
4151
4152 static void
4153 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4154 {
4155         GtkWidget *dialog;
4156         GtkWidget *align;
4157         GtkWidget *vbox;
4158         GtkWidget *priority_hbox;
4159         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4160         GtkWidget *captioned;
4161         GtkSizeGroup *title_sizegroup, *value_sizegroup;
4162         GtkWidget *format_hbox;
4163         GtkWidget *html_toggle, *text_toggle;
4164         ModestMsgEditWindowPrivate *priv;
4165         MessageSettingsHelper helper = {0,};
4166
4167         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4168         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4169         helper.window = window;
4170         helper.priority_group = NULL;
4171         helper.format_group = NULL;
4172
4173         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4174         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4175
4176         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4177                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4178                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4179         vbox = gtk_vbox_new (FALSE, 0);
4180         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4181         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4182         gtk_container_add (GTK_CONTAINER (align), vbox);
4183         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4184         gtk_widget_show (align);
4185         gtk_widget_show (vbox);
4186
4187         /* Priority toggles */
4188         priority_hbox = gtk_hbox_new (TRUE, 0);
4189         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4190         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4191         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4192         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4193         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4194         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4195         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4196         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4197         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4198         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4199         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4200         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4201         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4202         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4203         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4204         gtk_widget_show_all (priority_hbox);
4205         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4206                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4207         gtk_widget_show (captioned);
4208         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4209
4210         /* format toggles */
4211         format_hbox = gtk_hbox_new (TRUE, 0);
4212         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4213         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4214         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4215         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4216         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4217         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4218         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4219         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4220         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4221         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4222         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4223         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4224         gtk_widget_show_all (format_hbox);
4225         gtk_widget_show (format_hbox);
4226         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4227
4228
4229         g_object_unref (title_sizegroup);
4230         g_object_unref (value_sizegroup);
4231
4232         /* Set current values */
4233         switch (priv->priority_flags) {
4234         case TNY_HEADER_FLAG_HIGH_PRIORITY:
4235                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4236                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4237                 break;
4238         case TNY_HEADER_FLAG_LOW_PRIORITY:
4239                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4240                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4241                 break;
4242         default:
4243                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4244                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4245                 break;
4246         }
4247
4248         switch (modest_msg_edit_window_get_format (window)) {
4249         case MODEST_MSG_EDIT_FORMAT_TEXT:
4250                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4251                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4252                 break;
4253         case MODEST_MSG_EDIT_FORMAT_HTML:
4254         default:
4255                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4256                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4257                 break;
4258         }
4259
4260         /* Signal connects */
4261         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4262         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4263         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4264         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4265         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4266
4267         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
4268                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
4269
4270         /* Save settings if the user clicked on done */
4271         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4272                 TnyHeaderFlags flags;
4273                 ModestMsgEditFormat old_format, new_format;
4274
4275                 /* Set priority flags */
4276                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4277                 if (priv->priority_flags !=  flags)
4278                         modest_msg_edit_window_set_priority_flags (window, flags);
4279
4280                 /* Set edit format */
4281                 old_format = modest_msg_edit_window_get_format (window);
4282                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4283                 if (old_format != new_format) {
4284                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4285                         modest_msg_edit_window_set_file_format (window, file_format);
4286                 }
4287         }
4288
4289         gtk_widget_destroy (dialog);
4290         g_slist_free (helper.priority_group);
4291 }
4292
4293 static void
4294 on_message_settings (GtkAction *action,
4295                      ModestMsgEditWindow *window)
4296 {
4297         modest_msg_edit_window_show_msg_settings_dialog (window);
4298 }
4299
4300 static void
4301 on_cc_button_toggled (HildonCheckButton *button,
4302                       ModestMsgEditWindow *window)
4303 {
4304         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4305
4306         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4307                                         hildon_check_button_get_active (button));
4308 }
4309
4310 static void
4311 on_bcc_button_toggled (HildonCheckButton *button,
4312                       ModestMsgEditWindow *window)
4313 {
4314         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4315
4316         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4317                                         hildon_check_button_get_active (button));
4318 }
4319
4320 static void 
4321 setup_menu (ModestMsgEditWindow *self)
4322 {
4323         ModestMsgEditWindowPrivate *priv = NULL;
4324
4325         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4326
4327         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4328
4329         /* Settings menu buttons */
4330         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4331                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4332                                            NULL);
4333         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4334                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4335                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4336
4337         priv->cc_button = hildon_check_button_new (0);
4338         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4339         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4340                                         FALSE);
4341         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4342                                                   NULL);
4343         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4344                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4345         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4346         gtk_button_set_alignment (GTK_BUTTON (priv->cc_button), 0.5, 0.5);
4347
4348         priv->bcc_button = hildon_check_button_new (0);
4349         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4350         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4351                                         FALSE);
4352         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4353                                                   NULL);
4354         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4355                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4356         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4357         gtk_button_set_alignment (GTK_BUTTON (priv->bcc_button), 0.5, 0.5);
4358
4359         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4360                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4361                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4362         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_add_attachment"), NULL,
4363                                            APP_MENU_CALLBACK (modest_msg_edit_window_add_attachment_clicked),
4364                                            NULL);
4365         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4366                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4367                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4368         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4369                                            APP_MENU_CALLBACK (on_message_settings),
4370                                            NULL);
4371         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4372                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4373                                            NULL);
4374 }
4375
4376 static void
4377 emit_open_addressbook (GtkButton *button,
4378                        ModestRecptEditor *editor)
4379 {
4380         g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
4381 }
4382
4383 static GtkWidget *
4384 _create_addressbook_box (GtkSizeGroup *title_size_group, GtkSizeGroup *value_size_group,
4385                          const gchar *label, GtkWidget *control)
4386 {
4387         GtkWidget *abook_button;
4388         GtkWidget *align;
4389         GtkWidget *box;
4390         GtkWidget *label_widget;
4391
4392         box = gtk_hbox_new (FALSE, 0);
4393
4394         align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
4395         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, MODEST_MARGIN_DEFAULT);
4396
4397         abook_button = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT);
4398         label_widget = gtk_label_new (label);
4399         gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
4400         gtk_container_add (GTK_CONTAINER (abook_button), label_widget);
4401
4402         gtk_container_add (GTK_CONTAINER (align), abook_button);
4403         gtk_widget_set_size_request (label_widget, 148 - MODEST_MARGIN_DOUBLE, -1);
4404         gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 0);
4405         gtk_box_pack_start (GTK_BOX (box), control, TRUE, TRUE, 0);
4406         if (title_size_group)
4407                 gtk_size_group_add_widget (title_size_group, label_widget);
4408         if (value_size_group)
4409                 gtk_size_group_add_widget (value_size_group, control);
4410
4411         g_signal_connect (G_OBJECT (abook_button), "clicked",
4412                           G_CALLBACK (emit_open_addressbook), control);
4413   
4414         return box;  
4415 }
4416
4417 static void 
4418 max_chars_banner_unref (ModestMsgEditWindow *self, GObject *old_ref)
4419 {
4420         ModestMsgEditWindowPrivate *priv = NULL;
4421
4422         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4423
4424         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4425         priv->max_chars_banner = NULL;
4426 }