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