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