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