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