Remove mailbox signature on creating editor before setting a new one
[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         if (mailbox)
1686                 update_signature (MODEST_MSG_EDIT_WINDOW (obj), mailbox, NULL);
1687         update_signature (MODEST_MSG_EDIT_WINDOW (obj), account_name, priv->last_from_account);
1688
1689         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
1690
1691         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1692         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1693         modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1694         priv->update_caption_visibility = TRUE;
1695
1696         modest_msg_edit_window_set_modified (MODEST_MSG_EDIT_WINDOW (obj), FALSE);
1697
1698         /* Track account-removed signal, this window should be closed
1699            in the case we're creating a mail associated to the account
1700            that is deleted */
1701         priv->account_removed_handler_id = 
1702                 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
1703                                   "account_removed",
1704                                   G_CALLBACK(on_account_removed),
1705                                   obj);
1706
1707         modest_msg_edit_window_clipboard_owner_handle_change_in_idle (MODEST_MSG_EDIT_WINDOW (obj));
1708
1709         return (ModestWindow*) obj;
1710 }
1711
1712 static gint
1713 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1714 {
1715         GString **string_buffer = (GString **) user_data;
1716
1717         *string_buffer = g_string_append (*string_buffer, buffer);
1718    
1719         return 0;
1720 }
1721
1722 /**
1723  * @result: A new string which should be freed with g_free().
1724  */
1725 static gchar *
1726 get_formatted_data (ModestMsgEditWindow *edit_window)
1727 {
1728         ModestMsgEditWindowPrivate *priv;
1729         GString *string_buffer = g_string_new ("");
1730         
1731         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1732
1733         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1734
1735         modest_text_utils_hyperlinkify (string_buffer);
1736
1737         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1738
1739         return g_string_free (string_buffer, FALSE);
1740                                                                         
1741 }
1742
1743 MsgData * 
1744 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1745 {
1746         MsgData *data;
1747         const gchar *account_name;
1748         ModestMsgEditWindowPrivate *priv;
1749         TnyIterator *att_iter;
1750         const gchar *picker_active_id;
1751         
1752         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1753
1754         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1755         
1756         picker_active_id = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
1757         g_return_val_if_fail (picker_active_id, NULL);
1758         account_name = modest_utils_get_account_name_from_recipient (picker_active_id, NULL);
1759         
1760         /* don't free these (except from) */
1761         data = g_slice_new0 (MsgData);
1762         data->from    =  g_strdup ((gchar *) modest_selector_picker_get_active_display_name (MODEST_SELECTOR_PICKER (priv->from_field)));
1763         data->account_name = g_strdup (account_name);
1764         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1765         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1766         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1767         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1768         data->references = g_strdup (priv->references);
1769         data->in_reply_to = g_strdup (priv->in_reply_to);
1770         if (priv->draft_msg) {
1771                 data->draft_msg = g_object_ref (priv->draft_msg);
1772         } else if (priv->outbox_msg) {
1773                 data->draft_msg = g_object_ref (priv->outbox_msg);
1774         } else {
1775                 data->draft_msg = NULL;
1776         }
1777
1778         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1779         GtkTextIter b, e;
1780         gtk_text_buffer_get_bounds (buf, &b, &e);
1781         data->plain_body = modest_text_utils_text_buffer_get_text (priv->text_buffer); /* returns a copy */
1782
1783         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1784                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1785         else
1786                 data->html_body = NULL;
1787
1788         /* deep-copy the data */
1789         att_iter = tny_list_create_iterator (priv->attachments);
1790         data->attachments = NULL;
1791         while (!tny_iterator_is_done (att_iter)) {
1792                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1793                 if (!(TNY_IS_MIME_PART(part))) {
1794                         g_warning ("strange data in attachment list");
1795                         g_object_unref (part);
1796                         tny_iterator_next (att_iter);
1797                         continue;
1798                 }
1799                 data->attachments = g_list_append (data->attachments,
1800                                                    part);
1801                 tny_iterator_next (att_iter);
1802         }
1803         g_object_unref (att_iter);
1804
1805         GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (priv->text_buffer));
1806         att_iter = tny_list_create_iterator (priv->images);
1807         data->images = NULL;
1808         while (!tny_iterator_is_done (att_iter)) {
1809                 TnyMimePart *part = (TnyMimePart *) tny_iterator_get_current (att_iter);
1810                 const gchar *cid;
1811                 if (!(TNY_IS_MIME_PART(part))) {
1812                         g_warning ("strange data in attachment list");
1813                         g_object_unref (part);
1814                         tny_iterator_next (att_iter);
1815                         continue;
1816                 }
1817                 cid = tny_mime_part_get_content_id (part);
1818                 if (cid) {                      
1819                         gchar *image_tag_id;
1820                         GtkTextTag *image_tag;
1821                         GtkTextIter iter;
1822                         image_tag_id = g_strdup_printf ("image-tag-%s", cid);
1823                         image_tag = gtk_text_tag_table_lookup (tag_table, image_tag_id);
1824                         g_free (image_tag_id);
1825                         
1826                         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
1827                         if (image_tag && 
1828                             ((gtk_text_iter_has_tag (&iter, image_tag))||
1829                              (gtk_text_iter_forward_to_tag_toggle (&iter, image_tag))))
1830                                 data->images = g_list_append (data->images,
1831                                                               g_object_ref (part));
1832                 }
1833                 g_object_unref (part);
1834                 tny_iterator_next (att_iter);
1835         }
1836         g_object_unref (att_iter);
1837         
1838         data->priority_flags = priv->priority_flags;
1839
1840         return data;
1841 }
1842
1843
1844 static void
1845 unref_gobject (GObject *obj, gpointer data)
1846 {
1847         if (!G_IS_OBJECT(obj))
1848                 return;
1849         g_object_unref (obj);
1850 }
1851
1852 void 
1853 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1854                                                       MsgData *data)
1855 {
1856         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1857
1858         if (!data)
1859                 return;
1860
1861         g_free (data->to);
1862         g_free (data->cc);
1863         g_free (data->bcc);
1864         g_free (data->from);
1865         g_free (data->subject);
1866         g_free (data->plain_body);
1867         g_free (data->html_body);
1868         g_free (data->account_name);
1869         g_free (data->references);
1870         g_free (data->in_reply_to);
1871         
1872         if (data->draft_msg != NULL) {
1873                 g_object_unref (data->draft_msg);
1874                 data->draft_msg = NULL;
1875         }
1876         
1877         g_list_foreach (data->attachments, (GFunc)unref_gobject,  NULL);
1878         g_list_free (data->attachments);
1879         g_list_foreach (data->images, (GFunc)unref_gobject,  NULL);
1880         g_list_free (data->images);
1881         
1882         g_slice_free (MsgData, data);
1883 }
1884
1885 void                    
1886 modest_msg_edit_window_get_parts_size (ModestMsgEditWindow *window,
1887                                        gint *parts_count,
1888                                        guint64 *parts_size)
1889 {
1890         ModestMsgEditWindowPrivate *priv;
1891
1892         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1893
1894         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), parts_count, parts_size);
1895
1896         /* TODO: add images */
1897         *parts_size += priv->images_size;
1898         *parts_count += priv->images_count;
1899
1900 }
1901
1902 ModestMsgEditFormat
1903 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1904 {
1905         gboolean rich_text;
1906         ModestMsgEditWindowPrivate *priv = NULL;
1907         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1908
1909         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1910
1911         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1912         if (rich_text)
1913                 return MODEST_MSG_EDIT_FORMAT_HTML;
1914         else
1915                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1916 }
1917
1918 void
1919 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1920                                    ModestMsgEditFormat format)
1921 {
1922         ModestMsgEditWindowPrivate *priv;
1923
1924         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1925         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1926
1927         switch (format) {
1928         case MODEST_MSG_EDIT_FORMAT_HTML:
1929                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1930                 break;
1931         case MODEST_MSG_EDIT_FORMAT_TEXT:
1932                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1933                 break;
1934         default:
1935                 g_return_if_reached ();
1936         }
1937 }
1938
1939 ModestMsgEditFormatState *
1940 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1941 {
1942         ModestMsgEditFormatState *format_state = NULL;
1943         ModestMsgEditWindowPrivate *priv;
1944         WPTextBufferFormat *buffer_format;
1945
1946         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1947
1948         buffer_format = g_new0 (WPTextBufferFormat, 1);
1949         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1950
1951         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1952
1953         format_state = g_new0 (ModestMsgEditFormatState, 1);
1954         format_state->bold = buffer_format->bold&0x1;
1955         format_state->italics = buffer_format->italic&0x1;
1956         format_state->bullet = buffer_format->bullet&0x1;
1957         format_state->color = buffer_format->color;
1958         format_state->font_size = buffer_format->font_size;
1959         format_state->font_family = wp_get_font_name (buffer_format->font);
1960         format_state->justification = buffer_format->justification;
1961         g_free (buffer_format);
1962
1963         return format_state;
1964  
1965 }
1966
1967 void
1968 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1969                                          const ModestMsgEditFormatState *format_state)
1970 {
1971         ModestMsgEditWindowPrivate *priv;
1972         WPTextBufferFormat *buffer_format;
1973         WPTextBufferFormat *current_format;
1974
1975         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1976         g_return_if_fail (format_state != NULL);
1977
1978         buffer_format = g_new0 (WPTextBufferFormat, 1);
1979         current_format = g_new0 (WPTextBufferFormat, 1);
1980
1981         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1982         gtk_widget_grab_focus (priv->msg_body);
1983         buffer_format->bold = (format_state->bold != FALSE);
1984         buffer_format->italic = (format_state->italics != FALSE);
1985         buffer_format->color = format_state->color;
1986         buffer_format->font_size = format_state->font_size;
1987         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1988         buffer_format->justification = format_state->justification;
1989         buffer_format->bullet = format_state->bullet;
1990
1991         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1992
1993         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1994         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1995         buffer_format->cs.color = !gdk_color_equal(&(buffer_format->color), &(current_format->color));
1996         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1997         buffer_format->cs.font = (buffer_format->font != current_format->font);
1998         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1999         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
2000
2001         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
2002         if (buffer_format->cs.bold) {
2003                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD,
2004                                               GINT_TO_POINTER (buffer_format->bold&0x1));
2005         }
2006         if (buffer_format->cs.italic) {
2007                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC,
2008                                               GINT_TO_POINTER (buffer_format->italic&0x1));
2009         }
2010         if (buffer_format->cs.color) {
2011                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2012                                               GINT_TO_POINTER (&(buffer_format->color)));
2013         }
2014         if (buffer_format->cs.font_size) {
2015                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2016                                               GINT_TO_POINTER (buffer_format->font_size));
2017         }
2018         if (buffer_format->cs.justification) {
2019                 switch (buffer_format->justification) {
2020                 case GTK_JUSTIFY_LEFT:
2021                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT,
2022                                                       GINT_TO_POINTER(TRUE));
2023                         break;
2024                 case GTK_JUSTIFY_CENTER:
2025                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER,
2026                                                       GINT_TO_POINTER(TRUE));
2027                         break;
2028                 case GTK_JUSTIFY_RIGHT:
2029                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT,
2030                                                       GINT_TO_POINTER(TRUE));
2031                         break;
2032                 default:
2033                         break;
2034                 }
2035                         
2036         }
2037         if (buffer_format->cs.font) {
2038                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT,
2039                                               GINT_TO_POINTER (buffer_format->font));
2040         }
2041         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
2042         if (buffer_format->cs.bullet) {
2043                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET,
2044                                               GINT_TO_POINTER ((buffer_format->bullet)?1:0));
2045         }
2046 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
2047         
2048         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), self);
2049         
2050         g_free (buffer_format);
2051         g_free (current_format);
2052
2053         /* Check dimming rules */
2054         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2055         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2056 }
2057
2058 static void
2059 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
2060 {
2061         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2062         GtkAction *action;
2063         ModestWindowPrivate *parent_priv;
2064         ModestMsgEditWindowPrivate *priv;
2065         
2066         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2067         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2068
2069         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
2070                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu");
2071                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2072                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2073         } else {
2074                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatPlainTextMenu");
2075                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
2076                         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
2077         }
2078
2079         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2080
2081         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2082         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
2083
2084         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2085         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
2086
2087 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu"); */
2088 /*      modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); */
2089
2090         action = NULL;
2091         switch (buffer_format->justification)
2092         {
2093         case GTK_JUSTIFY_LEFT:
2094                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2095                 break;
2096         case GTK_JUSTIFY_CENTER:
2097                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2098                 break;
2099         case GTK_JUSTIFY_RIGHT:
2100                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2101                 break;
2102         default:
2103                 break;
2104         }
2105         
2106         if (action != NULL)
2107                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2108         
2109         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
2110                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
2111                                          window);
2112         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
2113         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
2114                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
2115                                            window);
2116
2117         if (priv->current_size_index != buffer_format->font_size) {
2118                 GtkTreeIter iter;
2119                 GtkTreePath *path;
2120
2121                 path = gtk_tree_path_new_from_indices (buffer_format->font_size, -1);
2122                 if (gtk_tree_model_get_iter (priv->sizes_model, &iter, path)) {
2123                         gchar *size_text;
2124                         gchar *markup;
2125
2126                         priv->current_size_index = buffer_format->font_size;
2127
2128                         gtk_tree_model_get (priv->sizes_model, &iter, 0, &size_text, -1);
2129                         markup = g_strconcat ("<span font_family='Sans'>", 
2130                                               size_text, "</span>", NULL);
2131                         
2132                         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2133                         g_free (markup);
2134                         g_free (size_text);
2135                 }
2136                 gtk_tree_path_free (path);              
2137         }
2138
2139         if (priv->current_face_index != buffer_format->font) {
2140                 GtkTreeIter iter;
2141                 GtkTreePath *path;
2142
2143                 path = gtk_tree_path_new_from_indices (buffer_format->font, -1);
2144                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2145                         gchar *face_name;
2146                         gchar *markup;
2147
2148                         priv->current_face_index = buffer_format->font;
2149                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2150                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2151                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2152                         g_free (face_name);
2153                         g_free (markup);
2154                 }
2155
2156         }
2157
2158         g_free (buffer_format);
2159
2160 }
2161
2162 #ifdef MODEST_HILDON_VERSION_0
2163 void
2164 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2165 {
2166         
2167         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2168         ModestMsgEditWindowPrivate *priv;
2169         GtkWidget *dialog = NULL;
2170         gint response;
2171         GdkColor *new_color = NULL;
2172
2173         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2174         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2175         
2176         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2177         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
2178         g_free (buffer_format);
2179
2180         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2181                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2182                 if (new_color != NULL) {
2183                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2184                                                       (gpointer) new_color);
2185                 }
2186         }
2187         gtk_widget_destroy (dialog);
2188 }
2189
2190
2191 void
2192 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2193 {
2194         
2195         ModestMsgEditWindowPrivate *priv;
2196         GtkWidget *dialog = NULL;
2197         gint response;
2198         GdkColor *old_color = NULL;
2199         const GdkColor *new_color = NULL;
2200         
2201         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2202         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2203         
2204         dialog = hildon_color_selector_new (GTK_WINDOW (window));
2205         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
2206
2207         if (gtk_dialog_run (GTK_DIALOG (dialog) == GTK_RESPONSE_OK)) {
2208                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
2209                 if (new_color != NULL)
2210                         wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
2211         }
2212         gtk_widget_destroy (dialog);
2213
2214 }
2215
2216 #else 
2217 void
2218 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
2219 {
2220         
2221         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
2222         ModestMsgEditWindowPrivate *priv;
2223         GtkWidget *dialog = NULL;
2224
2225         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2226         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
2227                 
2228         dialog = hildon_color_chooser_new ();
2229         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
2230         g_free (buffer_format);
2231
2232         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2233                 GdkColor col;
2234                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2235                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR,
2236                                               (gpointer) &col);
2237         }
2238         gtk_widget_destroy (dialog);
2239 }
2240
2241
2242 void
2243 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
2244 {
2245         
2246         ModestMsgEditWindowPrivate *priv;
2247         GtkWidget *dialog = NULL;
2248         GdkColor *old_color = NULL;
2249         
2250         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2251         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
2252         
2253         dialog = hildon_color_chooser_new ();
2254         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
2255
2256         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { 
2257                 GdkColor col;
2258                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
2259                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), &col);
2260         }
2261         gtk_widget_destroy (dialog);
2262 }
2263
2264 #endif /*!MODEST_HILDON_VERSION_0*/
2265
2266
2267
2268 static TnyStream*
2269 create_stream_for_uri (const gchar* uri)
2270 {
2271         if (!uri)
2272                 return NULL;
2273                 
2274         TnyStream *result = NULL;
2275
2276         GnomeVFSHandle *handle = NULL;
2277         GnomeVFSResult test = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2278         if (test == GNOME_VFS_OK) {
2279                 TnyStream *vfssstream = TNY_STREAM (tny_vfs_stream_new (handle));
2280                 /* Streams over OBEX (Bluetooth) are not seekable but
2281                  * we expect them to be (we might need to read them
2282                  * several times). So if this is a Bluetooth URI just
2283                  * read the whole file into memory (this is not a fast
2284                  * protocol so we can assume that these files are not
2285                  * going to be very big) */
2286                 if ((g_ascii_strncasecmp (uri, "obex://", 7) == 0)||
2287                     (g_ascii_strncasecmp (uri, "upnpav://", 9) == 0)) {
2288                         TnyStream *memstream = tny_camel_mem_stream_new ();
2289                         tny_stream_write_to_stream (vfssstream, memstream);
2290                         g_object_unref (vfssstream);
2291                         result = memstream;
2292                 } else {
2293                         result = vfssstream;
2294                 }
2295         }
2296         
2297         return result;
2298 }
2299
2300 void
2301 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
2302 {
2303         
2304         ModestMsgEditWindowPrivate *priv;
2305         GtkWidget *dialog = NULL;
2306         gint response = 0;
2307         GSList *uris = NULL;
2308         GSList *uri_node = NULL;
2309
2310         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2311
2312         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2313         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
2314         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2315
2316         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
2317
2318         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2319                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2320
2321         response = gtk_dialog_run (GTK_DIALOG (dialog));
2322         switch (response) {
2323         case GTK_RESPONSE_OK:
2324         {
2325                 gchar *current_folder;
2326                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2327                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2328                 if (current_folder && current_folder != '\0') {
2329                         GError *err = NULL;
2330                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_INSERT_IMAGE_PATH, 
2331                                                 current_folder, &err);
2332                         if (err != NULL) {
2333                                 g_debug ("Error storing latest used folder: %s", err->message);
2334                                 g_error_free (err);
2335                         }
2336                 }
2337                 g_free (current_folder);
2338         }
2339         break;
2340         default:
2341                 break;
2342         }
2343         gtk_widget_destroy (dialog);
2344
2345         g_object_ref (window);
2346         /* The operation could take some time so allow the dialog to be closed */
2347         while (gtk_events_pending ())
2348                 gtk_main_iteration ();
2349
2350         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2351                 const gchar *uri;
2352                 GnomeVFSHandle *handle = NULL;
2353                 GnomeVFSResult result;
2354                 GtkTextIter position;
2355                 GtkTextMark *insert_mark;
2356
2357                 uri = (const gchar *) uri_node->data;
2358                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2359                 if (result == GNOME_VFS_OK) {
2360                         GdkPixbuf *pixbuf;
2361                         GnomeVFSFileInfo *info;
2362                         gchar *filename, *basename, *escaped_filename;
2363                         TnyMimePart *mime_part;
2364                         gchar *content_id;
2365                         const gchar *mime_type = NULL;
2366                         GnomeVFSURI *vfs_uri;
2367                         guint64 stream_size;
2368
2369                         gnome_vfs_close (handle);
2370                         vfs_uri = gnome_vfs_uri_new (uri);
2371
2372                         escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2373                         filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2374                         g_free (escaped_filename);
2375                         gnome_vfs_uri_unref (vfs_uri);
2376                         info = gnome_vfs_file_info_new ();
2377
2378                         if (gnome_vfs_get_file_info (uri, info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE
2379                                                      | GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE) 
2380                             == GNOME_VFS_OK)
2381                                 mime_type = gnome_vfs_file_info_get_mime_type (info);
2382
2383                         mime_part = tny_platform_factory_new_mime_part
2384                                 (modest_runtime_get_platform_factory ());
2385
2386                         TnyStream *stream = create_stream_for_uri (uri);
2387
2388                         if (stream == NULL) {
2389
2390                                 modest_platform_information_banner (NULL, NULL, 
2391                                                                     _FM("sfil_ib_opening_not_allowed"));
2392                                 g_free (filename);
2393                                 g_object_unref (mime_part);
2394                                 gnome_vfs_file_info_unref (info);
2395                                 continue;
2396                         }
2397
2398                         tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2399
2400                         content_id = g_strdup_printf ("%d", priv->next_cid);
2401                         tny_mime_part_set_content_id (mime_part, content_id);
2402                         g_free (content_id);
2403                         priv->next_cid++;
2404
2405                         basename = g_path_get_basename (filename);
2406                         tny_mime_part_set_filename (mime_part, basename);
2407                         g_free (basename);
2408
2409                         pixbuf = pixbuf_from_stream (stream, mime_type, &stream_size, window);
2410
2411                         if (pixbuf != NULL) {
2412                                 priv->images_size += stream_size;
2413                                 priv->images_count ++;
2414                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
2415                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
2416                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, 
2417                                                              tny_mime_part_get_content_id (mime_part), pixbuf);
2418                                 g_object_unref (pixbuf);
2419
2420                                 tny_list_prepend (priv->images, (GObject *) mime_part);
2421                                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2422                         } else {
2423                                 modest_platform_information_banner (NULL, NULL,
2424                                                                     _("mail_ib_file_operation_failed"));
2425                         }
2426
2427                         g_free (filename);
2428                         g_object_unref (mime_part);
2429                         gnome_vfs_file_info_unref (info);
2430
2431                 }
2432         }
2433         g_object_unref (window);
2434 }
2435
2436 static void
2437 on_attach_file_response (GtkDialog *dialog,
2438                          gint       arg1,
2439                          gpointer   user_data)
2440 {
2441         GSList *uris = NULL;
2442         GSList *uri_node;
2443         GnomeVFSFileSize total_size, allowed_size;
2444         ModestMsgEditWindow *window;
2445         ModestMsgEditWindowPrivate *priv;
2446         gint att_num;
2447         guint64 att_size;
2448
2449         switch (arg1) {
2450         case GTK_RESPONSE_OK:
2451         {
2452                 gchar *current_folder;
2453
2454                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2455                 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2456                 if (current_folder && current_folder != '\0') {
2457                         GError *err = NULL;
2458                         modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, 
2459                                                 current_folder, &err);
2460                         if (err != NULL) {
2461                                 g_debug ("Error storing latest used folder: %s", err->message);
2462                                 g_error_free (err);
2463                         }
2464                 }
2465                 g_free (current_folder);
2466         }
2467         break;
2468         default:
2469                 break;
2470         }
2471
2472         window = MODEST_MSG_EDIT_WINDOW (user_data);
2473         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2474
2475         /* allowed size is the maximum size - what's already there */
2476         modest_attachments_view_get_sizes (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2477                                            &att_num, &att_size);
2478         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2479
2480         total_size = 0;
2481         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2482
2483                 const gchar *uri = (const gchar *) uri_node->data;
2484
2485                 total_size += 
2486                         modest_msg_edit_window_attach_file_one (window, uri, allowed_size);
2487
2488                 if (total_size > allowed_size) {
2489                         g_warning ("%s: total size: %u", 
2490                                    __FUNCTION__, (unsigned int)total_size);
2491                         break;
2492                 }
2493                 allowed_size -= total_size;
2494         }
2495         g_slist_foreach (uris, (GFunc) g_free, NULL);
2496         g_slist_free (uris);
2497
2498         gtk_widget_destroy (GTK_WIDGET (dialog));
2499 }
2500
2501 void
2502 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2503 {
2504         GtkWidget *dialog = NULL;
2505         ModestMsgEditWindowPrivate *priv;
2506         gchar *conf_folder;
2507
2508         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2509
2510         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2511
2512         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2513                 return;
2514
2515         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), 
2516                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
2517         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2518         conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_ATTACH_FILE_PATH, NULL);
2519         if (conf_folder && conf_folder[0] != '\0') {
2520                 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), conf_folder);
2521         } else {
2522                 gchar *docs_folder;
2523                 /* Set the default folder to images folder */
2524                 docs_folder = g_build_filename (g_getenv (MODEST_MAEMO_UTILS_MYDOCS_ENV),
2525                                                 ".documents", NULL);
2526                 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), docs_folder);
2527                 g_free (docs_folder);
2528         }
2529         g_free (conf_folder);
2530         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2531         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2532                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2533
2534         /* Connect to response & show */
2535         g_signal_connect (dialog, "response", 
2536                           G_CALLBACK (on_attach_file_response), window);
2537         gtk_widget_show (dialog);
2538 }
2539
2540
2541 GnomeVFSFileSize
2542 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2543                                         const gchar *uri, 
2544                                         GnomeVFSFileSize allowed_size)
2545
2546 {
2547         GnomeVFSHandle *handle = NULL;
2548         ModestMsgEditWindowPrivate *priv;
2549         GnomeVFSResult result;
2550         GnomeVFSFileSize size = 0;
2551         g_return_val_if_fail (window, 0);
2552         g_return_val_if_fail (uri, 0);
2553
2554         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2555
2556         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2557         if (result == GNOME_VFS_OK) {
2558                 TnyMimePart *mime_part;
2559                 TnyStream *stream;
2560                 const gchar *mime_type = NULL;
2561                 gchar *basename;
2562                 gchar *escaped_filename;
2563                 gchar *filename;
2564                 gchar *content_id;
2565                 GnomeVFSFileInfo *info;
2566                 GnomeVFSURI *vfs_uri;
2567
2568                 gnome_vfs_close (handle);
2569                 vfs_uri = gnome_vfs_uri_new (uri);
2570                 
2571
2572                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2573                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2574                 g_free (escaped_filename);
2575                 gnome_vfs_uri_unref (vfs_uri);
2576
2577                 info = gnome_vfs_file_info_new ();
2578                 
2579                 if (gnome_vfs_get_file_info (uri, 
2580                                              info, 
2581                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2582                     == GNOME_VFS_OK)
2583                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2584                 mime_part = tny_platform_factory_new_mime_part
2585                         (modest_runtime_get_platform_factory ());
2586                 
2587                 /* try to get the attachment's size; this may fail for weird
2588                  * file systems, like obex, upnp... */
2589                 if (allowed_size != 0 &&
2590                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2591                         size = info->size;
2592                         if (size > allowed_size) {
2593                                 modest_platform_information_banner (NULL, NULL, 
2594                                                                     _FM("sfil_ib_opening_not_allowed"));
2595                                 g_free (filename);
2596                                 return 0;
2597                         }
2598                 } else
2599                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2600                 
2601                 stream = create_stream_for_uri (uri);
2602                 
2603                 if (stream == NULL) {
2604
2605                         modest_platform_information_banner (NULL, NULL, _FM("sfil_ib_opening_not_allowed"));
2606
2607                         g_object_unref (mime_part);
2608                         g_free (filename);
2609                         gnome_vfs_file_info_unref (info);
2610                         return 0;
2611                 }
2612
2613                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2614                 g_object_unref (stream);
2615                 
2616                 content_id = g_strdup_printf ("%d", priv->next_cid);
2617                 tny_mime_part_set_content_id (mime_part, content_id);
2618                 g_free (content_id);
2619                 priv->next_cid++;
2620                 
2621                 basename = g_path_get_basename (filename);
2622                 tny_mime_part_set_filename (mime_part, basename);
2623                 g_free (basename);
2624                 
2625                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2626                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2627                                                         mime_part,
2628                                                         info->size == 0, info->size);
2629                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2630                 gtk_widget_show_all (priv->attachments_caption);
2631                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2632                 g_free (filename);
2633                 g_object_unref (mime_part);
2634                 gnome_vfs_file_info_unref (info);
2635         }
2636
2637         return size;
2638 }
2639
2640 void
2641 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2642                                            TnyList *att_list)
2643 {
2644         ModestMsgEditWindowPrivate *priv;
2645         TnyIterator *iter;
2646
2647         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2648         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2649
2650         if (att_list == NULL) {
2651                 att_list = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2652                 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), att_list, TRUE)) {
2653                         g_object_unref (att_list);
2654                         return;
2655                 }
2656                 
2657         } else {
2658                 g_object_ref (att_list);
2659         }
2660
2661         if (tny_list_get_length (att_list) == 0) {
2662                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2663         } else {
2664                 gboolean dialog_response;
2665                 gchar *message = NULL;
2666                 gchar *filename = NULL;
2667
2668                 if (tny_list_get_length (att_list) == 1) {
2669                         TnyMimePart *part;
2670                         iter = tny_list_create_iterator (att_list);
2671                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2672                         g_object_unref (iter);
2673                         if (TNY_IS_MSG (part)) {
2674                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2675                                 if (header) {
2676                                         filename = tny_header_dup_subject (header);
2677                                         g_object_unref (header);
2678                                 }
2679                                 if (filename == NULL) {
2680                                         filename = g_strdup (_("mail_va_no_subject"));
2681                                 }
2682                         } else {
2683                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2684                         }
2685                         g_object_unref (part);
2686                 } else {
2687                         filename = g_strdup ("");
2688                 }
2689                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", 
2690                                                     "emev_nc_delete_attachments",
2691                                                     tny_list_get_length (att_list)), filename);
2692                 g_free (filename);
2693
2694                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), 
2695                                                                            message);
2696                 g_free (message);
2697
2698                 if (dialog_response != GTK_RESPONSE_OK) {
2699                         g_object_unref (att_list);
2700                         return;
2701                 }
2702
2703                 for (iter = tny_list_create_iterator (att_list);
2704                      !tny_iterator_is_done (iter);
2705                      tny_iterator_next (iter)) {
2706                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2707                         const gchar *att_id;
2708                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2709
2710                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2711                                                                    mime_part);
2712                         if (tny_list_get_length (priv->attachments) == 0)
2713                                 gtk_widget_hide (priv->attachments_caption);
2714                         att_id = tny_mime_part_get_content_id (mime_part);
2715                         if (att_id != NULL)
2716                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2717                                                                  att_id);
2718                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2719                         g_object_unref (mime_part);
2720                 }
2721                 g_object_unref (iter);
2722         }
2723
2724         g_object_unref (att_list);
2725
2726         /* if the last attachment has been removed, focus the Subject: field */
2727         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2728                 gtk_widget_grab_focus (priv->subject_field);
2729 }
2730
2731 static void
2732 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2733                                             gpointer userdata)
2734 {
2735         ModestMsgEditWindowPrivate *priv;
2736         GdkColor *new_color;
2737         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2738         
2739 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2740         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2741 #else 
2742         GdkColor col;
2743         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2744         new_color = &col;
2745 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2746
2747         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2748         
2749         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2750
2751 }
2752
2753 static void
2754 font_size_clicked (GtkToolButton *button,
2755                    ModestMsgEditWindow *window)
2756 {
2757         ModestMsgEditWindowPrivate *priv;
2758         GtkWidget *selector, *dialog;
2759         
2760         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2761
2762         selector = hildon_touch_selector_new ();
2763         hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector), priv->sizes_model, TRUE);
2764         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_size_index);
2765
2766         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2767         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2768         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_size"));
2769
2770         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2771                 gint new_index;
2772                 gchar *size_text;
2773                 gchar *markup;
2774                 WPTextBufferFormat format;
2775
2776                 new_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2777
2778                 memset (&format, 0, sizeof (format));
2779                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2780
2781                 format.cs.font_size = TRUE;
2782                 format.cs.text_position = TRUE;
2783                 format.cs.font = TRUE;
2784                 format.font_size = new_index;
2785 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2786
2787                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2788                                                    GINT_TO_POINTER (new_index)))
2789                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2790                 
2791                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2792                 size_text = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
2793                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", 
2794                                       size_text, "</span>", NULL);
2795                 g_free (size_text);
2796                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2797                 g_free (markup);
2798
2799         }
2800         gtk_widget_destroy (dialog);
2801
2802         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2803
2804 }
2805
2806 static void
2807 font_face_clicked (GtkToolButton *button,
2808                    ModestMsgEditWindow *window)
2809 {
2810         ModestMsgEditWindowPrivate *priv;
2811         GtkWidget *selector, *dialog;
2812         GtkCellRenderer *renderer;
2813         
2814         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2815
2816         selector = hildon_touch_selector_new ();
2817         renderer = gtk_cell_renderer_text_new ();
2818         hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), priv->faces_model, 
2819                                              renderer, "family", 0, "text", 0, NULL);
2820         hildon_touch_selector_set_active (HILDON_TOUCH_SELECTOR (selector), 0, priv->current_face_index);
2821
2822         dialog = hildon_picker_dialog_new (GTK_WINDOW (window));
2823         hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (dialog), HILDON_TOUCH_SELECTOR (selector));
2824         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_font_face"));
2825
2826         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
2827                 gint new_font_index;
2828                 GtkTreePath *path;
2829                 GtkTreeIter iter;
2830
2831                 new_font_index = hildon_touch_selector_get_active (HILDON_TOUCH_SELECTOR (selector), 0);
2832                 path = gtk_tree_path_new_from_indices (new_font_index, -1);
2833                 if (gtk_tree_model_get_iter (priv->faces_model, &iter, path)) {
2834                         gchar *face_name;
2835                         gchar *markup;
2836
2837                         gtk_tree_model_get (priv->faces_model, &iter, 0, &face_name, -1);
2838
2839                         if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2840                                                            GINT_TO_POINTER(new_font_index)))
2841                                 wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2842
2843                         markup = g_strconcat ("<span font_family='", face_name, "'>Tt</span>", NULL);
2844                         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2845
2846                         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2847                         g_free (face_name);
2848                         g_free (markup);
2849                 }
2850                 gtk_tree_path_free (path);
2851
2852         }
2853         gtk_widget_destroy (dialog);
2854
2855         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2856
2857 }
2858
2859 void
2860 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2861                                 gboolean show)
2862 {
2863         ModestMsgEditWindowPrivate *priv = NULL;
2864         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2865
2866         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2867         if (!priv->update_caption_visibility)
2868                 return;
2869
2870         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2871         if (show)
2872                 gtk_widget_show (priv->cc_caption);
2873         else
2874                 gtk_widget_hide (priv->cc_caption);
2875
2876         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2877 }
2878
2879 void
2880 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2881                                  gboolean show)
2882 {
2883         ModestMsgEditWindowPrivate *priv = NULL;
2884         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2885
2886         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2887         if (!priv->update_caption_visibility)
2888                 return;
2889
2890         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2891         if (show)
2892                 gtk_widget_show (priv->bcc_caption);
2893         else
2894                 gtk_widget_hide (priv->bcc_caption);
2895
2896         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2897 }
2898
2899 static void
2900 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2901                                          ModestRecptEditor *editor)
2902 {
2903         ModestMsgEditWindowPrivate *priv;
2904
2905         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2906         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2907         
2908         /* we check for low-mem; in that case, show a warning, and don't allow
2909          * for the addressbook
2910          */
2911         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2912                 return;
2913
2914         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2915
2916         if (editor == NULL) {
2917                 GtkWidget *view_focus;
2918                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2919
2920                 /* This code should be kept in sync with ModestRecptEditor. The
2921                    textview inside the recpt editor is the one that really gets the
2922                    focus. As it's inside a scrolled window, and this one inside the
2923                    hbox recpt editor inherits from, we'll need to go up in the 
2924                    hierarchy to know if the text view is part of the recpt editor
2925                    or if it's a different text entry */
2926
2927                 if (gtk_widget_get_parent (view_focus)) {
2928                         GtkWidget *first_parent;
2929
2930                         first_parent = gtk_widget_get_parent (view_focus);
2931                         if (gtk_widget_get_parent (first_parent) && 
2932                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2933                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2934                         }
2935                 }
2936
2937                 if (editor == NULL)
2938                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2939
2940         }
2941
2942         modest_address_book_select_addresses (editor);
2943
2944 }
2945
2946 void
2947 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2948 {
2949         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2950
2951         modest_msg_edit_window_open_addressbook (window, NULL);
2952 }
2953
2954 static void
2955 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2956                                      gboolean show_toolbar)
2957 {
2958         ModestWindowPrivate *parent_priv;
2959
2960         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2961         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2962
2963         /* We can not just use the code of
2964            modest_msg_edit_window_setup_toolbar because it has a
2965            mixture of both initialization and creation code. */
2966         if (show_toolbar)
2967                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2968         else
2969                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2970 }
2971
2972 void
2973 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2974                                            TnyHeaderFlags priority_flags)
2975 {
2976         ModestMsgEditWindowPrivate *priv;
2977         ModestWindowPrivate *parent_priv;
2978
2979         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2980
2981         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2982         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2983
2984         if (priv->priority_flags != priority_flags) {
2985                 GtkAction *priority_action = NULL;
2986
2987                 priv->priority_flags = priority_flags;
2988
2989                 switch (priority_flags) {
2990                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2991                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2992                                                       MODEST_HEADER_ICON_HIGH, 
2993                                                       HILDON_ICON_SIZE_SMALL);
2994                         gtk_widget_show (priv->priority_icon);
2995                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2996                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2997                         break;
2998                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2999                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
3000                                                       MODEST_HEADER_ICON_LOW,
3001                                                       HILDON_ICON_SIZE_SMALL);
3002                         gtk_widget_show (priv->priority_icon);
3003                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3004                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
3005                         break;
3006                 default:
3007                         gtk_widget_hide (priv->priority_icon);
3008                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
3009                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
3010                         break;
3011                 }
3012                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
3013                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3014         }
3015         gtk_widget_queue_resize (priv->subject_box);
3016 }
3017
3018 void
3019 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
3020                                         gint file_format)
3021 {
3022         ModestMsgEditWindowPrivate *priv;
3023         ModestWindowPrivate *parent_priv;
3024         gint current_format;
3025
3026         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3027
3028         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
3029         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3030
3031         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
3032                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
3033
3034         if (current_format != file_format) {
3035                 switch (file_format) {
3036                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
3037                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
3038                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
3039                         break;
3040                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
3041                 {
3042                         GtkWidget *dialog;
3043                         gint response;
3044                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
3045                         response = gtk_dialog_run (GTK_DIALOG (dialog));
3046                         gtk_widget_destroy (dialog);
3047                         if (response == GTK_RESPONSE_OK) {
3048                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
3049                         } else {
3050                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
3051                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
3052                         }
3053                 }
3054                         break;
3055                 }
3056                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3057                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3058                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3059         }
3060 }
3061
3062 void
3063 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
3064 {
3065         GtkWidget *dialog;
3066         ModestMsgEditWindowPrivate *priv;
3067         WPTextBufferFormat oldfmt, fmt;
3068         gint old_position = 0;
3069         gint response = 0;
3070         gint position = 0;
3071         gint font_size;
3072         GdkColor *color = NULL;
3073         gboolean bold, bold_set, italic, italic_set;
3074         gboolean underline, underline_set;
3075         gboolean strikethrough, strikethrough_set;
3076         gboolean position_set;
3077         gboolean font_size_set, font_set, color_set;
3078         gchar *font_name;
3079
3080         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3081         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3082         
3083         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
3084         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
3085                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
3086
3087         /* First we get the currently selected font information */
3088         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
3089
3090         switch (oldfmt.text_position) {
3091         case TEXT_POSITION_NORMAL:
3092                 old_position = 0;
3093                 break;
3094         case TEXT_POSITION_SUPERSCRIPT:
3095                 old_position = 1;
3096                 break;
3097         default:
3098                 old_position = -1;
3099                 break;
3100         }
3101
3102         g_object_set (G_OBJECT (dialog),
3103                       "bold", oldfmt.bold != FALSE,
3104                       "bold-set", !oldfmt.cs.bold,
3105                       "underline", oldfmt.underline != FALSE,
3106                       "underline-set", !oldfmt.cs.underline,
3107                       "italic", oldfmt.italic != FALSE,
3108                       "italic-set", !oldfmt.cs.italic,
3109                       "strikethrough", oldfmt.strikethrough != FALSE,
3110                       "strikethrough-set", !oldfmt.cs.strikethrough,
3111                       "color", &oldfmt.color,
3112                       "color-set", !oldfmt.cs.color,
3113                       "size", wp_font_size[oldfmt.font_size],
3114                       "size-set", !oldfmt.cs.font_size,
3115                       "position", old_position,
3116                       "position-set", !oldfmt.cs.text_position,
3117                       "family", wp_get_font_name (oldfmt.font),
3118                       "family-set", !oldfmt.cs.font,
3119                       NULL);
3120
3121         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
3122                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
3123         gtk_widget_show_all (dialog);
3124         priv->font_dialog = dialog;
3125         response = gtk_dialog_run (GTK_DIALOG (dialog));
3126         priv->font_dialog = NULL;
3127         if (response == GTK_RESPONSE_OK) {
3128
3129                 g_object_get( dialog,
3130                               "bold", &bold,
3131                               "bold-set", &bold_set,
3132                               "underline", &underline,
3133                               "underline-set", &underline_set,
3134                               "italic", &italic,
3135                               "italic-set", &italic_set,
3136                               "strikethrough", &strikethrough,
3137                               "strikethrough-set", &strikethrough_set,
3138                               "color", &color,
3139                               "color-set", &color_set,
3140                               "size", &font_size,
3141                               "size-set", &font_size_set,
3142                               "family", &font_name,
3143                               "family-set", &font_set,
3144                               "position", &position,
3145                               "position-set", &position_set,
3146                               NULL );
3147                 
3148         }       
3149
3150         if (response == GTK_RESPONSE_OK) {
3151                 memset(&fmt, 0, sizeof(fmt));
3152                 if (bold_set) {
3153                         fmt.bold = bold;
3154                         fmt.cs.bold = TRUE;
3155                 }
3156                 if (italic_set) {
3157                         fmt.italic = italic;
3158                         fmt.cs.italic = TRUE;
3159                 }
3160                 if (underline_set) {
3161                         fmt.underline = underline;
3162                         fmt.cs.underline = TRUE;
3163                 }
3164                 if (strikethrough_set) {
3165                         fmt.strikethrough = strikethrough;
3166                         fmt.cs.strikethrough = TRUE;
3167                 }
3168                 if (position_set) {
3169                         fmt.text_position =
3170                                 ( position == 0 )
3171                                 ? TEXT_POSITION_NORMAL
3172                                 : ( ( position == 1 )
3173                                     ? TEXT_POSITION_SUPERSCRIPT
3174                                     : TEXT_POSITION_SUBSCRIPT );
3175                         fmt.cs.text_position = TRUE;
3176                         fmt.font_size = oldfmt.font_size;
3177                 }
3178                 if (color_set) {
3179                         fmt.color = *color;
3180                         fmt.cs.color = TRUE;
3181                 }
3182                 if (font_set) {
3183                         fmt.font = wp_get_font_index(font_name,
3184                                                      DEFAULT_FONT);
3185                         fmt.cs.font = TRUE;
3186                 }
3187                 g_free(font_name);
3188                 if (font_size_set) {
3189                         fmt.cs.font_size = TRUE;
3190                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
3191                 }
3192                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
3193                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
3194         }
3195         gtk_widget_destroy (dialog);
3196         
3197         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
3198 }
3199
3200 void
3201 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
3202 {
3203         ModestMsgEditWindowPrivate *priv;
3204
3205         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3206         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3207         
3208         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
3209
3210         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3211         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3212 }
3213
3214 void
3215 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
3216 {
3217         ModestMsgEditWindowPrivate *priv;
3218
3219         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3220         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3221         
3222         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
3223
3224         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3225         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3226
3227 }
3228
3229 static void  
3230 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
3231 {
3232         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3233
3234         priv->can_undo = can_undo;
3235 }
3236
3237 static void  
3238 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
3239 {
3240         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3241
3242         priv->can_redo = can_redo;
3243 }
3244
3245 gboolean            
3246 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
3247 {
3248         ModestMsgEditWindowPrivate *priv;
3249         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3250         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3251
3252         return priv->can_undo;
3253 }
3254
3255 gboolean            
3256 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
3257 {
3258         ModestMsgEditWindowPrivate *priv;
3259         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3260         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3261
3262         return priv->can_redo;
3263 }
3264
3265
3266 static void
3267 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
3268 {
3269         GtkTextIter iter;
3270         GtkTextIter match_start, match_end;
3271
3272         if (image_id == NULL)
3273                 return;
3274
3275         gtk_text_buffer_get_start_iter (buffer, &iter);
3276
3277         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
3278                 GSList *tags = gtk_text_iter_get_tags (&match_start);
3279                 GSList *node;
3280                 for (node = tags; node != NULL; node = g_slist_next (node)) {
3281                         GtkTextTag *tag = (GtkTextTag *) node->data;
3282                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
3283                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
3284                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
3285                                         gint offset;
3286                                         offset = gtk_text_iter_get_offset (&match_start);
3287                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
3288                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
3289                                 }
3290                         }
3291                 }
3292                 gtk_text_iter_forward_char (&iter);
3293         }
3294 }
3295
3296 gboolean
3297 message_is_empty (ModestMsgEditWindow *window)
3298 {
3299         ModestMsgEditWindowPrivate *priv = NULL;
3300
3301         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3302         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3303
3304         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3305          * so we can ignore markup.
3306          */
3307         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3308         gint count = 0;
3309         if (buf)
3310                 count = gtk_text_buffer_get_char_count (buf);
3311
3312         return count == 0;
3313 }
3314
3315 static gboolean
3316 msg_body_focus (GtkWidget *focus,
3317                 GdkEventFocus *event,
3318                 gpointer userdata)
3319 {
3320         
3321         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3322         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3323         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3324         return FALSE;
3325 }
3326
3327 static void
3328 recpt_field_changed (GtkTextBuffer *buffer,
3329                   ModestMsgEditWindow *editor)
3330 {
3331         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3332         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3333 }
3334
3335 static void
3336 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3337 {
3338         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3339         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3340 }
3341
3342 void
3343 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3344                                      gboolean modified)
3345 {
3346         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3347         GtkTextBuffer *buffer;
3348
3349         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3350         gtk_text_buffer_set_modified (buffer, modified);
3351         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3352         gtk_text_buffer_set_modified (buffer, modified);
3353         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3354         gtk_text_buffer_set_modified (buffer, modified);
3355         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3356 }
3357
3358 gboolean
3359 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3360 {
3361         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3362         const char *account_name;
3363         GtkTextBuffer *buffer;
3364
3365         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3366         if (gtk_text_buffer_get_modified (buffer))
3367                 return TRUE;
3368         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3369         if (gtk_text_buffer_get_modified (buffer))
3370                 return TRUE;
3371         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3372         if (gtk_text_buffer_get_modified (buffer))
3373                 return TRUE;
3374         if (gtk_text_buffer_get_modified (priv->text_buffer))
3375                 return TRUE;
3376
3377         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3378         if (priv->original_mailbox) {
3379                 if (!account_name || strcmp (account_name, priv->original_mailbox))
3380                         return TRUE;
3381         } else if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3382                 return TRUE;
3383         }
3384
3385         return FALSE;
3386 }
3387
3388
3389
3390
3391 gboolean
3392 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3393 {
3394         ModestMsgEditWindowPrivate *priv = NULL;
3395         
3396         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3397         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3398
3399         /* check if there's no recipient added */
3400         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3401             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3402             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3403                 /* no recipient contents, then select contacts */
3404                 modest_msg_edit_window_open_addressbook (window, NULL);
3405                 return FALSE;
3406         }
3407
3408         g_object_ref (window);
3409         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3410                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3411                 g_object_unref (window);
3412                 return FALSE;
3413         }
3414         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3415                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3416                 g_object_unref (window);
3417                 return FALSE;
3418         }
3419         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3420                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3421                 g_object_unref (window);
3422                 return FALSE;
3423         }
3424
3425         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3426             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3427                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3428         g_object_unref (window);
3429
3430         return TRUE;
3431
3432 }
3433
3434 static void
3435 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3436                                                ModestMsgEditWindow *window)
3437 {
3438         modest_msg_edit_window_offer_attach_file (window);
3439 }
3440
3441 const gchar *
3442 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3443 {
3444         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3445
3446         return priv->clipboard_text;
3447 }
3448
3449 static void
3450 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3451                                                GdkEvent *event,
3452                                                ModestMsgEditWindow *window)
3453 {
3454         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3455         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3456         gchar *text = NULL;
3457
3458         /* It could happen that the window was already closed */
3459         if (!GTK_WIDGET_VISIBLE (window))
3460                 return;
3461
3462         g_object_ref (window);
3463         text = gtk_clipboard_wait_for_text (selection_clipboard);
3464
3465         if (priv->clipboard_text != NULL) {
3466                 g_free (priv->clipboard_text);
3467         }
3468         priv->clipboard_text = text;
3469
3470         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3471
3472         g_object_unref (window);
3473 }
3474
3475 static gboolean clipboard_owner_change_idle (gpointer userdata)
3476 {
3477         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3478         ModestMsgEditWindowPrivate *priv;
3479
3480         gdk_threads_enter ();
3481         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3482         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3483
3484         priv->clipboard_owner_idle = 0;
3485         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3486         gdk_threads_leave ();
3487
3488         return FALSE;
3489 }
3490
3491 static void
3492 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3493 {
3494         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3495         if (priv->clipboard_owner_idle == 0) {
3496                 priv->clipboard_owner_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
3497                                                               clipboard_owner_change_idle, 
3498                                                               g_object_ref (window),
3499                                                               g_object_unref);
3500         }
3501 }
3502
3503 static void 
3504 subject_field_move_cursor (GtkEntry *entry,
3505                            GtkMovementStep step,
3506                            gint a1,
3507                            gboolean a2,
3508                            gpointer window)
3509 {
3510         /* It could happen that the window was already closed */
3511         if (!GTK_WIDGET_VISIBLE (window))
3512                 return;
3513
3514         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3515 }
3516
3517 static void 
3518 update_window_title (ModestMsgEditWindow *window)
3519 {
3520         ModestMsgEditWindowPrivate *priv = NULL;
3521         const gchar *subject;
3522
3523         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3524         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3525         if (subject == NULL || subject[0] == '\0')
3526                 subject = _("mail_va_new_email");
3527
3528         gtk_window_set_title (GTK_WINDOW (window), subject);
3529
3530 }
3531
3532 static void  
3533 subject_field_changed (GtkEditable *editable, 
3534                        ModestMsgEditWindow *window)
3535 {
3536         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3537         update_window_title (window);
3538         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3539         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3540         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3541 }
3542
3543 static void  
3544 subject_field_insert_text (GtkEditable *editable, 
3545                            gchar *new_text,
3546                            gint new_text_length,
3547                            gint *position,
3548                            ModestMsgEditWindow *window)
3549 {
3550         GString *result = g_string_new ("");
3551         gchar *current;
3552         gint result_len = 0;
3553         const gchar *entry_text = NULL;
3554         gint old_length;
3555
3556         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3557         old_length = g_utf8_strlen (entry_text, -1);
3558
3559         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3560                 gunichar c = g_utf8_get_char_validated (current, 8);
3561                 /* Invalid unichar, stop */
3562                 if (c == -1)
3563                         break;
3564                 /* a bullet */
3565                 if (c == 0x2022)
3566                         continue;
3567                 result = g_string_append_unichar (result, c);
3568                 result_len++;
3569         }
3570
3571         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3572                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3573                 if (result_len > 0)
3574                 {
3575                         /* Prevent endless recursion */
3576                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3577                         g_signal_emit_by_name (editable, "insert-text", 
3578                                                (gpointer) result->str, (gpointer) result->len,
3579                                                (gpointer) position, (gpointer) window);
3580                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3581                 }
3582         }
3583
3584         if (result_len + old_length > 1000) {
3585                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3586                                                 _CS("ckdg_ib_maximum_characters_reached"));
3587         }
3588         g_string_free (result, TRUE);
3589 }
3590
3591 void
3592 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3593                                             gboolean show)
3594 {
3595         ModestMsgEditWindowPrivate *priv = NULL;
3596
3597         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3598         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3599
3600         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3601
3602         if (show) {
3603                 gtk_widget_show_all (priv->find_toolbar);
3604                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3605         } else {
3606                 gtk_widget_hide_all (priv->find_toolbar);
3607                 gtk_widget_grab_focus (priv->msg_body);
3608         }
3609 }
3610
3611 static gboolean 
3612 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3613                                           const gchar *str,
3614                                           GtkTextIter *match_start,
3615                                           GtkTextIter *match_end)
3616 {
3617         GtkTextIter end_iter;
3618         gchar *str_casefold;
3619         gint str_chars_n;
3620         gchar *range_text;
3621         gchar *range_casefold;
3622         gint offset;
3623         gint range_chars_n;
3624         gboolean result = FALSE;
3625
3626         if (str == NULL)
3627                 return TRUE;
3628         
3629         /* get end iter */
3630         end_iter = *iter;
3631         gtk_text_iter_forward_to_end (&end_iter);
3632
3633         str_casefold = g_utf8_casefold (str, -1);
3634         str_chars_n = strlen (str);
3635
3636         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3637         range_casefold = g_utf8_casefold (range_text, -1);
3638         range_chars_n = strlen (range_casefold);
3639
3640         if (range_chars_n < str_chars_n) {
3641                 g_free (str_casefold);
3642                 g_free (range_text);
3643                 g_free (range_casefold);
3644                 return FALSE;
3645         }
3646
3647         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3648                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3649                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3650                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3651                         result = TRUE;
3652                         if (!gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3653                                                            match_start, match_end, NULL)) {
3654                                 g_warning ("Matched string with collate, but not matched in model");
3655                         }
3656                         g_free (found_text);
3657                 }
3658                 g_free (range_subtext);
3659                 if (result)
3660                         break;
3661         }
3662         g_free (str_casefold);
3663         g_free (range_text);
3664         g_free (range_casefold);
3665
3666         return result;
3667 }
3668
3669
3670 static void 
3671 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3672                                             ModestMsgEditWindow *window)
3673 {
3674         gchar *current_search = NULL;
3675         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3676         gboolean result;
3677         GtkTextIter selection_start, selection_end;
3678         GtkTextIter match_start, match_end;
3679         gboolean continue_search = FALSE;
3680
3681         if (message_is_empty (window)) {
3682                 g_free (priv->last_search);
3683                 priv->last_search = NULL;
3684                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3685                 return;
3686         }
3687
3688         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3689         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3690                 g_free (current_search);
3691                 g_free (priv->last_search);
3692                 priv->last_search = NULL;
3693                 /* Information banner about empty search */
3694                 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
3695                 return;
3696         }
3697
3698         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3699                 continue_search = TRUE;
3700         } else {
3701                 g_free (priv->last_search);
3702                 priv->last_search = g_strdup (current_search);
3703         }
3704
3705         if (continue_search) {
3706                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3707                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3708                                                                    &match_start, &match_end);
3709                 if (!result)
3710                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
3711         } else {
3712                 GtkTextIter buffer_start;
3713                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3714                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3715                                                                    &match_start, &match_end);
3716                 if (!result)
3717                         hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
3718         }
3719
3720         /* Mark as selected the string found in search */
3721         if (result) {
3722                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3723                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3724                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3725         } else {
3726                 g_free (priv->last_search);
3727                 priv->last_search = NULL;
3728         }
3729         g_free (current_search);
3730 }
3731
3732 gboolean 
3733 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3734 {
3735         ModestMsgEditWindowPrivate *priv;
3736
3737         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3738         return priv->sent;
3739 }
3740
3741 void 
3742 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3743                                  gboolean sent)
3744 {
3745         ModestMsgEditWindowPrivate *priv;
3746
3747         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3748         priv->sent = sent;
3749 }
3750
3751 static void
3752 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3753                                           ModestMsgEditWindow *window)
3754 {
3755         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3756 }
3757
3758 void
3759 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3760                                   TnyMsg *draft)
3761 {
3762         ModestMsgEditWindowPrivate *priv;
3763         TnyHeader *header = NULL;
3764
3765         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3766         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3767
3768         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3769
3770         if (priv->draft_msg != NULL) {
3771                 g_object_unref (priv->draft_msg);
3772         }
3773
3774         if (draft != NULL) {
3775                 g_object_ref (draft);
3776                 header = tny_msg_get_header (draft);
3777                 if (priv->msg_uid) {
3778                         g_free (priv->msg_uid);
3779                         priv->msg_uid = NULL;
3780                 }
3781                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3782         }
3783
3784         priv->draft_msg = draft;
3785 }
3786
3787 static void  
3788 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3789                        GtkTextIter *start, GtkTextIter *end,
3790                        gpointer userdata)
3791 {
3792         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3793         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3794         gchar *tag_name;
3795
3796         if (tag == NULL) return;
3797         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3798         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3799                 replace_with_images (window, priv->images);
3800         }
3801 }
3802
3803 void                    
3804 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3805                                  TnyMimePart *part)
3806 {
3807         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3808
3809         g_return_if_fail (TNY_IS_MIME_PART (part));
3810         tny_list_prepend (priv->attachments, (GObject *) part);
3811         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3812         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3813         gtk_widget_show_all (priv->attachments_caption);
3814         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3815 }
3816
3817 const gchar*    
3818 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3819 {
3820         ModestMsgEditWindowPrivate *priv;
3821
3822         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3823         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3824
3825         return priv->msg_uid;
3826 }
3827
3828 GtkWidget *
3829 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3830                                          ModestMsgEditWindowWidgetType widget_type)
3831 {
3832         ModestMsgEditWindowPrivate *priv;
3833
3834         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3835         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3836
3837         switch (widget_type) {
3838         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3839                 return priv->msg_body;
3840                 break;
3841         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3842                 return priv->to_field;
3843                 break;
3844         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3845                 return priv->cc_field;
3846                 break;
3847         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3848                 return priv->bcc_field;
3849                 break;
3850         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3851                 return priv->subject_field;
3852                 break;
3853         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3854                 return priv->attachments_view;
3855                 break;
3856         default:
3857                 return NULL;
3858         }
3859 }
3860
3861 static void 
3862 remove_tags (WPTextBuffer *buffer)
3863 {
3864         GtkTextIter start, end;
3865
3866         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3867         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3868
3869         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3870 }
3871
3872 static void
3873 on_account_removed (TnyAccountStore *account_store, 
3874                     TnyAccount *account,
3875                     gpointer user_data)
3876 {
3877         /* Do nothing if it's a store account, because we use the
3878            transport to send the messages */
3879         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3880                 const gchar *parent_acc = NULL;
3881                 const gchar *our_acc = NULL;
3882
3883                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3884                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3885                 /* Close this window if I'm showing a message of the removed account */
3886                 if (strcmp (parent_acc, our_acc) == 0)
3887                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3888         }
3889 }
3890
3891 static gchar *
3892 get_signature (const gchar *current_recipient, gboolean *has_signature)
3893 {
3894         gchar *result = NULL;
3895         gchar *mailbox = NULL;
3896         gchar *account_name;
3897         ModestProtocol *protocol = NULL;
3898
3899         *has_signature = FALSE;
3900
3901         account_name = modest_utils_get_account_name_from_recipient (current_recipient, &mailbox);
3902         if (account_is_multimailbox (account_name, &protocol)
3903             && mailbox) {
3904                 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3905                         result = modest_account_protocol_get_signature (MODEST_ACCOUNT_PROTOCOL (protocol),
3906                                                                         account_name, mailbox, 
3907                                                                         has_signature);
3908                 }
3909         }
3910
3911         if (result == NULL) {
3912                 result = modest_account_mgr_get_signature (modest_runtime_get_account_mgr (), 
3913                                                            account_name, has_signature);
3914         }
3915         return result;
3916 }
3917
3918 static void update_signature (ModestMsgEditWindow *self,
3919                               const gchar *old_account, 
3920                               const gchar *new_account)
3921 {
3922         ModestMsgEditWindowPrivate *priv;
3923         gboolean has_old_signature, has_new_signature;
3924         GtkTextIter iter;
3925         GtkTextIter match_start, match_end;
3926         ModestAccountMgr *mgr;
3927         gchar *signature;
3928         gchar *full_signature;
3929
3930         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3931
3932         gtk_text_buffer_begin_user_action (priv->text_buffer);
3933
3934         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
3935         mgr = modest_runtime_get_account_mgr ();
3936
3937
3938         if (old_account) {
3939                 signature = get_signature (old_account, &has_old_signature);
3940                 if (has_old_signature) {
3941                         full_signature = g_strconcat ("\n--\n", signature, NULL);
3942                         if (gtk_text_iter_forward_search (&iter, full_signature, 0, &match_start, &match_end, NULL)) {
3943                                 gtk_text_buffer_delete (priv->text_buffer, &match_start, &match_end);
3944                                 iter = match_start;
3945                         } else if (gtk_text_iter_forward_search (&iter, _("mcen_ia_editor_original_message"), 0,
3946                                                                  &match_start, &match_end, NULL)) {
3947                                 iter = match_start;
3948                         }
3949                         g_free (full_signature);
3950                 }
3951                 g_free (signature);
3952         }
3953
3954         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3955         signature = get_signature (new_account, &has_new_signature);
3956         if (has_new_signature) {
3957                 full_signature = g_strconcat ("\n--\n", signature, NULL);
3958                 gtk_text_buffer_insert (priv->text_buffer, &iter, full_signature, -1);
3959                 g_free (full_signature);
3960         }
3961         g_free (signature);
3962         gtk_text_buffer_end_user_action (priv->text_buffer);
3963 }
3964
3965 static void
3966 from_field_changed (HildonPickerButton *button,
3967                     ModestMsgEditWindow *self)
3968 {
3969         ModestMsgEditWindowPrivate *priv;
3970         gchar *old_account, *new_account;
3971
3972         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3973
3974         old_account = priv->last_from_account;
3975         priv->last_from_account = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3976         new_account = priv->last_from_account;
3977
3978         update_signature (self, old_account, new_account);
3979
3980 }
3981
3982 typedef struct _MessageSettingsHelper {
3983         ModestMsgEditWindow *window;
3984         GSList *priority_group;
3985         GSList *format_group;
3986         GtkToggleButton *current_priority;
3987         GtkToggleButton *current_format;
3988 } MessageSettingsHelper;
3989
3990 static void
3991 on_priority_toggle (GtkToggleButton *button, 
3992                     MessageSettingsHelper *helper)
3993 {
3994         GSList *node;
3995         ModestMsgEditWindowPrivate *priv;
3996
3997         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3998         if (gtk_toggle_button_get_active (button)) {
3999
4000                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4001                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4002                         if ((node_button != button) &&
4003                             gtk_toggle_button_get_active (node_button)) {
4004                                 gtk_toggle_button_set_active (node_button, FALSE);
4005                         }
4006                 }
4007                 helper->current_priority = button;
4008         } else {
4009                 gboolean found = FALSE;
4010                 /* If no one is active, activate it again */
4011                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
4012                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4013                         if (gtk_toggle_button_get_active (node_button)) {
4014                                 found = TRUE;
4015                                 break;
4016                         }
4017                 }
4018                 if (!found) {
4019                         gtk_toggle_button_set_active (button, TRUE);
4020                 }
4021         }
4022 }
4023
4024 static void
4025 on_format_toggle (GtkToggleButton *button,
4026                   MessageSettingsHelper *helper)
4027 {
4028         GSList *node;
4029         ModestMsgEditWindowPrivate *priv;
4030
4031         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
4032         if (gtk_toggle_button_get_active (button)) {
4033
4034                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4035                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4036                         if ((node_button != button) &&
4037                             gtk_toggle_button_get_active (node_button)) {
4038                                 gtk_toggle_button_set_active (node_button, FALSE);
4039                         }
4040                 }
4041                 helper->current_format = button;
4042         } else {
4043                 gboolean found = FALSE;
4044                 /* If no one is active, activate it again */
4045                 for (node = helper->format_group; node != NULL; node = g_slist_next (node)) {
4046                         GtkToggleButton *node_button = (GtkToggleButton *) node->data;
4047                         if (gtk_toggle_button_get_active (node_button)) {
4048                                 found = TRUE;
4049                                 break;
4050                         }
4051                 }
4052                 if (!found) {
4053                         gtk_toggle_button_set_active (button, TRUE);
4054                 }
4055         }
4056
4057 }
4058
4059 static void
4060 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
4061 {
4062         GtkWidget *dialog;
4063         GtkWidget *align;
4064         GtkWidget *vbox;
4065         GtkWidget *priority_hbox;
4066         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
4067         GtkWidget *captioned;
4068         GtkSizeGroup *title_sizegroup, *value_sizegroup;
4069         GtkWidget *format_hbox;
4070         GtkWidget *html_toggle, *text_toggle;
4071         ModestMsgEditWindowPrivate *priv;
4072         MessageSettingsHelper helper = {0,};
4073
4074         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
4075         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
4076         helper.window = window;
4077         helper.priority_group = NULL;
4078         helper.format_group = NULL;
4079
4080         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4081         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
4082
4083         dialog = gtk_dialog_new_with_buttons (_("mcen_me_message_settings"), NULL,
4084                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4085                                               _HL("wdgt_bd_done"), GTK_RESPONSE_ACCEPT, NULL);
4086         vbox = gtk_vbox_new (FALSE, 0);
4087         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
4088         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE, 0);
4089         gtk_container_add (GTK_CONTAINER (align), vbox);
4090         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), align);
4091         gtk_widget_show (align);
4092         gtk_widget_show (vbox);
4093
4094         /* Priority toggles */
4095         priority_hbox = gtk_hbox_new (TRUE, 0);
4096         high_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4097         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
4098         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
4099         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
4100         medium_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4101         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
4102         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
4103         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
4104         low_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4105         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
4106         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
4107         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
4108         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, TRUE, TRUE, 0);
4109         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, TRUE, TRUE, 0);
4110         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, TRUE, TRUE, 0);
4111         gtk_widget_show_all (priority_hbox);
4112         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
4113                                                          _("mcen_me_editor_message_priority"), FALSE, priority_hbox);
4114         gtk_widget_show (captioned);
4115         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
4116
4117         /* format toggles */
4118         format_hbox = gtk_hbox_new (TRUE, 0);
4119         html_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4120         gtk_button_set_label (GTK_BUTTON (html_toggle), _("mcen_me_editor_formatted_text"));
4121         helper.format_group = g_slist_prepend (helper.format_group, html_toggle);
4122         g_object_set_data (G_OBJECT (html_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_HTML));
4123         g_object_set_data (G_OBJECT (html_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_FORMATTED_TEXT));
4124         text_toggle = hildon_gtk_toggle_button_new (HILDON_SIZE_FINGER_HEIGHT);
4125         gtk_button_set_label (GTK_BUTTON (text_toggle), _("mcen_me_editor_plain_text"));
4126         helper.format_group = g_slist_prepend (helper.format_group, text_toggle);
4127         g_object_set_data (G_OBJECT (text_toggle), "format", GINT_TO_POINTER (MODEST_MSG_EDIT_FORMAT_TEXT));
4128         g_object_set_data (G_OBJECT (text_toggle), "file-format", GINT_TO_POINTER (MODEST_FILE_FORMAT_PLAIN_TEXT));
4129         gtk_box_pack_start (GTK_BOX (format_hbox), html_toggle, TRUE, TRUE, 0);
4130         gtk_box_pack_start (GTK_BOX (format_hbox), text_toggle, TRUE, TRUE, 0);
4131         gtk_widget_show_all (format_hbox);
4132         gtk_widget_show (format_hbox);
4133         gtk_box_pack_start (GTK_BOX (vbox), format_hbox, FALSE, FALSE, 0);
4134
4135
4136         g_object_unref (title_sizegroup);
4137         g_object_unref (value_sizegroup);
4138
4139         /* Set current values */
4140         switch (priv->priority_flags) {
4141         case TNY_HEADER_FLAG_HIGH_PRIORITY:
4142                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (high_toggle), TRUE);
4143                 helper.current_priority = GTK_TOGGLE_BUTTON (high_toggle);
4144                 break;
4145         case TNY_HEADER_FLAG_LOW_PRIORITY:
4146                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (low_toggle), TRUE);
4147                 helper.current_priority = GTK_TOGGLE_BUTTON (low_toggle);
4148                 break;
4149         default:
4150                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (medium_toggle), TRUE);
4151                 helper.current_priority = GTK_TOGGLE_BUTTON (medium_toggle);
4152                 break;
4153         }
4154
4155         switch (modest_msg_edit_window_get_format (window)) {
4156         case MODEST_MSG_EDIT_FORMAT_TEXT:
4157                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_toggle), TRUE);
4158                 helper.current_format = GTK_TOGGLE_BUTTON (text_toggle);
4159                 break;
4160         case MODEST_MSG_EDIT_FORMAT_HTML:
4161         default:
4162                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (html_toggle), TRUE);
4163                 helper.current_format = GTK_TOGGLE_BUTTON (html_toggle);
4164                 break;
4165         }
4166
4167         /* Signal connects */
4168         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4169         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4170         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
4171         g_signal_connect (G_OBJECT (html_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4172         g_signal_connect (G_OBJECT (text_toggle), "toggled", G_CALLBACK (on_format_toggle), &helper);
4173
4174         /* Save settings if the user clicked on done */
4175         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
4176                 TnyHeaderFlags flags;
4177                 ModestMsgEditFormat old_format, new_format;
4178
4179                 /* Set priority flags */
4180                 flags = (TnyHeaderFlags) g_object_get_data (G_OBJECT (helper.current_priority), "priority");
4181                 if (priv->priority_flags !=  flags)
4182                         modest_msg_edit_window_set_priority_flags (window, flags);
4183
4184                 /* Set edit format */
4185                 old_format = modest_msg_edit_window_get_format (window);
4186                 new_format = (ModestMsgEditFormat) g_object_get_data (G_OBJECT (helper.current_format), "format");
4187                 if (old_format != new_format) {
4188                         gint file_format = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (helper.current_format), "file-format"));
4189                         modest_msg_edit_window_set_file_format (window, file_format);
4190                 }
4191         }
4192
4193         gtk_widget_destroy (dialog);
4194         g_slist_free (helper.priority_group);
4195 }
4196
4197 static void
4198 on_message_settings (GtkAction *action,
4199                      ModestMsgEditWindow *window)
4200 {
4201         modest_msg_edit_window_show_msg_settings_dialog (window);
4202 }
4203
4204 static void
4205 on_cc_button_toggled (HildonCheckButton *button,
4206                       ModestMsgEditWindow *window)
4207 {
4208         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4209
4210         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
4211                                         hildon_check_button_get_active (button));
4212 }
4213
4214 static void
4215 on_bcc_button_toggled (HildonCheckButton *button,
4216                       ModestMsgEditWindow *window)
4217 {
4218         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
4219
4220         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
4221                                         hildon_check_button_get_active (button));
4222 }
4223
4224 static void 
4225 setup_menu (ModestMsgEditWindow *self)
4226 {
4227         ModestMsgEditWindowPrivate *priv = NULL;
4228
4229         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
4230
4231         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
4232
4233         /* Settings menu buttons */
4234         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
4235                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
4236                                            NULL);
4237         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
4238                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
4239                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
4240
4241         priv->cc_button = hildon_check_button_new (0);
4242         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
4243         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
4244                                         FALSE);
4245         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
4246                                                   NULL);
4247         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
4248                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
4249         priv->bcc_button = hildon_check_button_new (0);
4250         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
4251         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
4252                                         FALSE);
4253         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
4254                                                   NULL);
4255         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
4256                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
4257
4258         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
4259                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
4260                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
4261         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
4262                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
4263                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
4264         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
4265                                            APP_MENU_CALLBACK (on_message_settings),
4266                                            NULL);
4267         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
4268                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
4269                                            NULL);
4270 }
4271