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