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