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