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