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