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