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