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