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