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