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