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