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