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