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