6029f4b8bc74d844ad31f3a8dd81cc8c18ac7fbb
[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 void
2223 modest_msg_edit_window_offer_attach_file (ModestMsgEditWindow *window)
2224 {       
2225         GtkWidget *dialog = NULL;
2226         gint response = 0;
2227         GSList *uris = NULL;
2228         GSList *uri_node;
2229         GnomeVFSFileSize total_size, allowed_size;
2230         ModestMsgEditWindowPrivate *priv;
2231         gint att_num;
2232         guint64 att_size;
2233
2234         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(window));
2235                 
2236         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2237
2238         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2239                 return;
2240         
2241         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
2242         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ti_select_attachment_title"));
2243         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
2244         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog), GTK_WINDOW (window));
2245
2246         response = gtk_dialog_run (GTK_DIALOG (dialog));
2247         switch (response) {
2248         case GTK_RESPONSE_OK:
2249                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
2250                 break;
2251         default:
2252                 break;
2253         }
2254         gtk_widget_destroy (dialog);
2255
2256         /* allowed size is the maximum size - what's already there */
2257         modest_attachments_view_get_sizes (
2258                 MODEST_ATTACHMENTS_VIEW (priv->attachments_view), 
2259                 &att_num, &att_size);
2260         allowed_size = MODEST_MAX_ATTACHMENT_SIZE - att_size;
2261
2262         total_size = 0;
2263         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
2264
2265                 const gchar *uri = (const gchar *) uri_node->data;
2266                 
2267                 total_size += modest_msg_edit_window_attach_file_one 
2268                         (window, uri, allowed_size);
2269                 
2270                 if (total_size > allowed_size) {
2271                         g_warning ("%s: total size: %u", 
2272                                    __FUNCTION__, (unsigned int)total_size);
2273                         break;
2274                 }
2275
2276                 allowed_size -= total_size;
2277                 
2278
2279         }
2280         g_slist_foreach (uris, (GFunc) g_free, NULL);
2281         g_slist_free (uris);
2282 }
2283
2284
2285 GnomeVFSFileSize
2286 modest_msg_edit_window_attach_file_one (ModestMsgEditWindow *window,
2287                                         const gchar *uri, 
2288                                         GnomeVFSFileSize allowed_size)
2289
2290 {
2291         GnomeVFSHandle *handle = NULL;
2292         ModestMsgEditWindowPrivate *priv;
2293         GnomeVFSResult result;
2294         GnomeVFSFileSize size = 0;
2295         g_return_val_if_fail (window, 0);
2296         g_return_val_if_fail (uri, 0);
2297                 
2298         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2299         
2300         result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
2301         if (result == GNOME_VFS_OK) {
2302                 TnyMimePart *mime_part;
2303                 TnyStream *stream;
2304                 const gchar *mime_type = NULL;
2305                 gchar *basename;
2306                 gchar *escaped_filename;
2307                 gchar *filename;
2308                 gchar *content_id;
2309                 GnomeVFSFileInfo *info;
2310                 GnomeVFSURI *vfs_uri;
2311
2312                 gnome_vfs_close (handle);
2313                 vfs_uri = gnome_vfs_uri_new (uri);
2314                 
2315
2316                 escaped_filename = g_path_get_basename (gnome_vfs_uri_get_path (vfs_uri));
2317                 filename = gnome_vfs_unescape_string_for_display (escaped_filename);
2318                 g_free (escaped_filename);
2319                 gnome_vfs_uri_unref (vfs_uri);
2320
2321                 info = gnome_vfs_file_info_new ();
2322                 
2323                 if (gnome_vfs_get_file_info (uri, 
2324                                              info, 
2325                                              GNOME_VFS_FILE_INFO_GET_MIME_TYPE)
2326                     == GNOME_VFS_OK)
2327                         mime_type = gnome_vfs_file_info_get_mime_type (info);
2328                 mime_part = tny_platform_factory_new_mime_part
2329                         (modest_runtime_get_platform_factory ());
2330                 
2331                 /* try to get the attachment's size; this may fail for weird
2332                  * file systems, like obex, upnp... */
2333                 if (allowed_size != 0 &&
2334                     info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
2335                         size = info->size;
2336                         if (size > allowed_size) {
2337                                 modest_platform_information_banner (NULL, NULL, 
2338                                                                     dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2339                                 return 0;
2340                         }
2341                 } else
2342                         g_warning ("%s: could not get attachment size", __FUNCTION__);
2343                 
2344                 stream = create_stream_for_uri (uri);
2345                 
2346                 if (stream == NULL) {
2347
2348                         modest_platform_information_banner (NULL, NULL, dgettext("hildon-fm", "sfil_ib_opening_not_allowed"));
2349
2350                         g_object_unref (mime_part);
2351                         gnome_vfs_file_info_unref (info);
2352                         return 0;
2353                 }
2354
2355                 tny_mime_part_construct (mime_part, stream, mime_type, "base64");
2356                 g_object_unref (stream);
2357                 
2358                 content_id = g_strdup_printf ("%d", priv->next_cid);
2359                 tny_mime_part_set_content_id (mime_part, content_id);
2360                 g_free (content_id);
2361                 priv->next_cid++;
2362                 
2363                 basename = g_path_get_basename (filename);
2364                 tny_mime_part_set_filename (mime_part, basename);
2365                 g_free (basename);
2366                 
2367                 tny_list_prepend (priv->attachments, (GObject *) mime_part);
2368                 modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2369                                                         mime_part,
2370                                                         info->size == 0, info->size);
2371                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
2372                 gtk_widget_show_all (priv->attachments_caption);
2373                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2374                 g_free (filename);
2375                 g_object_unref (mime_part);
2376                 gnome_vfs_file_info_unref (info);
2377         }
2378
2379         return size;
2380 }
2381
2382 void
2383 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
2384                                            TnyList *att_list)
2385 {
2386         ModestMsgEditWindowPrivate *priv;
2387         TnyIterator *iter;
2388
2389         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2390         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2391
2392         if (att_list == NULL) {
2393                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2394         } else {
2395                 g_object_ref (att_list);
2396         }
2397
2398         if (tny_list_get_length (att_list) == 0) {
2399                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
2400         } else {
2401                 gboolean dialog_response;
2402                 gchar *message = NULL;
2403                 gchar *filename = NULL;
2404
2405                 if (tny_list_get_length (att_list) == 1) {
2406                         TnyMimePart *part;
2407                         iter = tny_list_create_iterator (att_list);
2408                         part = (TnyMimePart *) tny_iterator_get_current (iter);
2409                         g_object_unref (iter);
2410                         if (TNY_IS_MSG (part)) {
2411                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (part));
2412                                 if (header) {
2413                                         filename = tny_header_dup_subject (header);
2414                                         g_object_unref (header);
2415                                 }
2416                                 if (filename == NULL) {
2417                                         filename = g_strdup (_("mail_va_no_subject"));
2418                                 }
2419                         } else {
2420                                 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
2421                         }
2422                         g_object_unref (part);
2423                 } else {
2424                         filename = g_strdup ("");
2425                 }
2426                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
2427                                                     tny_list_get_length (att_list)), filename);
2428                 g_free (filename);
2429
2430                 dialog_response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window), message);
2431                 g_free (message);
2432
2433                 if (dialog_response != GTK_RESPONSE_OK) {
2434                         g_object_unref (att_list);
2435                         return;
2436                 }
2437                 hildon_banner_show_information (NULL, NULL, _("mcen_me_inbox_remove_attachments"));
2438                 
2439                 for (iter = tny_list_create_iterator (att_list);
2440                      !tny_iterator_is_done (iter);
2441                      tny_iterator_next (iter)) {
2442                         TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2443                         const gchar *att_id;
2444                         tny_list_remove (priv->attachments, (GObject *) mime_part);
2445
2446                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2447                                                                    mime_part);
2448                         if (tny_list_get_length (priv->attachments) == 0)
2449                                 gtk_widget_hide (priv->attachments_caption);
2450                         att_id = tny_mime_part_get_content_id (mime_part);
2451                         if (att_id != NULL)
2452                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
2453                                                                  att_id);
2454                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2455                         g_object_unref (mime_part);
2456                 }
2457                 g_object_unref (iter);
2458         }
2459
2460         g_object_unref (att_list);
2461
2462         /* if the last attachment has been removed, focus the Subject: field */
2463         if (!modest_attachments_view_has_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view))) 
2464                 gtk_widget_grab_focus (priv->subject_field);
2465 }
2466
2467 static void
2468 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
2469                                             gpointer userdata)
2470 {
2471         ModestMsgEditWindowPrivate *priv;
2472         GdkColor *new_color;
2473         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2474         
2475 #ifdef MODEST_HAVE_HILDON0_WIDGETS      
2476         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
2477 #else 
2478         GdkColor col;
2479         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
2480         new_color = &col;
2481 #endif /*#ifdef MODEST_HAVE_HILDON0_WIDGETS*/
2482
2483         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
2484         
2485         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
2486
2487 }
2488
2489 static void
2490 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
2491                                     gpointer userdata)
2492 {
2493         ModestMsgEditWindowPrivate *priv;
2494         gint new_size_index;
2495         ModestMsgEditWindow *window;
2496         GtkWidget *label;
2497         
2498         window = MODEST_MSG_EDIT_WINDOW (userdata);
2499         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2500         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2501
2502         if (gtk_check_menu_item_get_active (menu_item)) {
2503                 gchar *markup;
2504                 WPTextBufferFormat format;
2505
2506                 memset (&format, 0, sizeof (format));
2507                 wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &format, FALSE);
2508
2509                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2510                 
2511                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
2512                 format.cs.font_size = TRUE;
2513                 format.cs.text_position = TRUE;
2514                 format.cs.font = TRUE;
2515                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
2516 /*              wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format); */
2517
2518                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE,
2519                                                    GINT_TO_POINTER (wp_get_font_size_index (new_size_index, 12))))
2520                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2521                 
2522                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2523                 markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
2524                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
2525                 g_free (markup);
2526         }
2527 }
2528
2529 static void
2530 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
2531                                     gpointer userdata)
2532 {
2533         ModestMsgEditWindowPrivate *priv;
2534         gint new_font_index;
2535         ModestMsgEditWindow *window;
2536         GtkWidget *label;
2537         
2538         window = MODEST_MSG_EDIT_WINDOW (userdata);
2539         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2540         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
2541
2542         if (gtk_check_menu_item_get_active (menu_item)) {
2543                 gchar *markup;
2544
2545                 label = gtk_bin_get_child (GTK_BIN (menu_item));
2546                 
2547                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
2548
2549                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
2550                                                    GINT_TO_POINTER(new_font_index)))
2551                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
2552                 
2553                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
2554                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
2555                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
2556                 g_free (markup);
2557         }
2558 }
2559
2560 void
2561 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
2562                                 gboolean show)
2563 {
2564         ModestMsgEditWindowPrivate *priv = NULL;
2565         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2566
2567         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2568         if (!priv->update_caption_visibility)
2569                 return;
2570
2571         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
2572         if (show)
2573                 gtk_widget_show (priv->cc_caption);
2574         else
2575                 gtk_widget_hide (priv->cc_caption);
2576
2577         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
2578 }
2579
2580 void
2581 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
2582                                  gboolean show)
2583 {
2584         ModestMsgEditWindowPrivate *priv = NULL;
2585         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2586
2587         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2588         if (!priv->update_caption_visibility)
2589                 return;
2590
2591         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2592         if (show)
2593                 gtk_widget_show (priv->bcc_caption);
2594         else
2595                 gtk_widget_hide (priv->bcc_caption);
2596
2597         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2598 }
2599
2600 static void
2601 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2602                                          ModestRecptEditor *editor)
2603 {
2604         ModestMsgEditWindowPrivate *priv;
2605
2606         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2607         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2608         
2609         /* we check for low-mem; in that case, show a warning, and don't allow
2610          * for the addressbook
2611          */
2612         if (modest_platform_check_memory_low (MODEST_WINDOW(window), TRUE))
2613                 return;
2614
2615         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2616
2617         if (editor == NULL) {
2618                 GtkWidget *view_focus;
2619                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2620
2621                 /* This code should be kept in sync with ModestRecptEditor. The
2622                    textview inside the recpt editor is the one that really gets the
2623                    focus. As it's inside a scrolled window, and this one inside the
2624                    hbox recpt editor inherits from, we'll need to go up in the 
2625                    hierarchy to know if the text view is part of the recpt editor
2626                    or if it's a different text entry */
2627
2628                 if (gtk_widget_get_parent (view_focus)) {
2629                         GtkWidget *first_parent;
2630
2631                         first_parent = gtk_widget_get_parent (view_focus);
2632                         if (gtk_widget_get_parent (first_parent) && 
2633                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2634                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2635                         }
2636                 }
2637
2638                 if (editor == NULL)
2639                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2640
2641         }
2642
2643         modest_address_book_select_addresses (editor);
2644
2645 }
2646
2647 void
2648 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2649 {
2650         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2651
2652         modest_msg_edit_window_open_addressbook (window, NULL);
2653 }
2654
2655 static void
2656 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2657                                      gboolean show_toolbar)
2658 {
2659         ModestWindowPrivate *parent_priv;
2660
2661         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2662         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2663
2664         /* We can not just use the code of
2665            modest_msg_edit_window_setup_toolbar because it has a
2666            mixture of both initialization and creation code. */
2667         if (show_toolbar)
2668                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2669         else
2670                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2671 }
2672
2673 void
2674 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2675                                            TnyHeaderFlags priority_flags)
2676 {
2677         ModestMsgEditWindowPrivate *priv;
2678         ModestWindowPrivate *parent_priv;
2679
2680         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2681
2682         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2683         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2684
2685         if (priv->priority_flags != priority_flags) {
2686                 GtkAction *priority_action = NULL;
2687
2688                 priv->priority_flags = priority_flags;
2689
2690                 switch (priority_flags) {
2691                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2692                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2693                                                       MODEST_HEADER_ICON_HIGH, 
2694                                                       HILDON_ICON_SIZE_XSMALL);
2695                         gtk_widget_show (priv->priority_icon);
2696                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2697                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2698                         break;
2699                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2700                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon),
2701                                                       MODEST_HEADER_ICON_LOW,
2702                                                       HILDON_ICON_SIZE_XSMALL);
2703                         gtk_widget_show (priv->priority_icon);
2704                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2705                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2706                         break;
2707                 default:
2708                         gtk_widget_hide (priv->priority_icon);
2709                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager,
2710                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2711                         break;
2712                 }
2713                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2714                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2715         }
2716 }
2717
2718 void
2719 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2720                                         gint file_format)
2721 {
2722         ModestMsgEditWindowPrivate *priv;
2723         ModestWindowPrivate *parent_priv;
2724         gint current_format;
2725
2726         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2727
2728         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2729         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2730
2731         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2732                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2733
2734         if (current_format != file_format) {
2735                 switch (file_format) {
2736                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2737                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2738                         remove_tags (WP_TEXT_BUFFER (priv->text_buffer));
2739                         break;
2740                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2741                 {
2742                         GtkWidget *dialog;
2743                         gint response;
2744                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2745                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2746                         gtk_widget_destroy (dialog);
2747                         if (response == GTK_RESPONSE_OK) {
2748                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2749                         } else {
2750                                 GtkToggleAction *action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatFormattedTextMenu"));
2751                                 modest_utils_toggle_action_set_active_block_notify (action, TRUE);
2752                         }
2753                 }
2754                         break;
2755                 }
2756                 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2757                 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2758                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2759         }
2760 }
2761
2762 void
2763 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2764 {
2765         GtkWidget *dialog;
2766         ModestMsgEditWindowPrivate *priv;
2767         WPTextBufferFormat oldfmt, fmt;
2768         gint old_position = 0;
2769         gint response = 0;
2770         gint position = 0;
2771         gint font_size;
2772         GdkColor *color = NULL;
2773         gboolean bold, bold_set, italic, italic_set;
2774         gboolean underline, underline_set;
2775         gboolean strikethrough, strikethrough_set;
2776         gboolean position_set;
2777         gboolean font_size_set, font_set, color_set;
2778         gchar *font_name;
2779
2780         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2781         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2782         
2783         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2784         modest_window_mgr_set_modal (modest_runtime_get_window_mgr(),
2785                                      GTK_WINDOW(dialog), GTK_WINDOW (window));
2786
2787         /* First we get the currently selected font information */
2788         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2789
2790         switch (oldfmt.text_position) {
2791         case TEXT_POSITION_NORMAL:
2792                 old_position = 0;
2793                 break;
2794         case TEXT_POSITION_SUPERSCRIPT:
2795                 old_position = 1;
2796                 break;
2797         default:
2798                 old_position = -1;
2799                 break;
2800         }
2801
2802         g_object_set (G_OBJECT (dialog),
2803                       "bold", oldfmt.bold != FALSE,
2804                       "bold-set", !oldfmt.cs.bold,
2805                       "underline", oldfmt.underline != FALSE,
2806                       "underline-set", !oldfmt.cs.underline,
2807                       "italic", oldfmt.italic != FALSE,
2808                       "italic-set", !oldfmt.cs.italic,
2809                       "strikethrough", oldfmt.strikethrough != FALSE,
2810                       "strikethrough-set", !oldfmt.cs.strikethrough,
2811                       "color", &oldfmt.color,
2812                       "color-set", !oldfmt.cs.color,
2813                       "size", wp_font_size[oldfmt.font_size],
2814                       "size-set", !oldfmt.cs.font_size,
2815                       "position", old_position,
2816                       "position-set", !oldfmt.cs.text_position,
2817                       "family", wp_get_font_name (oldfmt.font),
2818                       "family-set", !oldfmt.cs.font,
2819                       NULL);
2820
2821         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), 
2822                                      GTK_WINDOW (dialog), GTK_WINDOW (window));
2823         gtk_widget_show_all (dialog);
2824         priv->font_dialog = dialog;
2825         response = gtk_dialog_run (GTK_DIALOG (dialog));
2826         priv->font_dialog = NULL;
2827         if (response == GTK_RESPONSE_OK) {
2828
2829                 g_object_get( dialog,
2830                               "bold", &bold,
2831                               "bold-set", &bold_set,
2832                               "underline", &underline,
2833                               "underline-set", &underline_set,
2834                               "italic", &italic,
2835                               "italic-set", &italic_set,
2836                               "strikethrough", &strikethrough,
2837                               "strikethrough-set", &strikethrough_set,
2838                               "color", &color,
2839                               "color-set", &color_set,
2840                               "size", &font_size,
2841                               "size-set", &font_size_set,
2842                               "family", &font_name,
2843                               "family-set", &font_set,
2844                               "position", &position,
2845                               "position-set", &position_set,
2846                               NULL );
2847                 
2848         }       
2849
2850         if (response == GTK_RESPONSE_OK) {
2851                 memset(&fmt, 0, sizeof(fmt));
2852                 if (bold_set) {
2853                         fmt.bold = bold;
2854                         fmt.cs.bold = TRUE;
2855                 }
2856                 if (italic_set) {
2857                         fmt.italic = italic;
2858                         fmt.cs.italic = TRUE;
2859                 }
2860                 if (underline_set) {
2861                         fmt.underline = underline;
2862                         fmt.cs.underline = TRUE;
2863                 }
2864                 if (strikethrough_set) {
2865                         fmt.strikethrough = strikethrough;
2866                         fmt.cs.strikethrough = TRUE;
2867                 }
2868                 if (position_set) {
2869                         fmt.text_position =
2870                                 ( position == 0 )
2871                                 ? TEXT_POSITION_NORMAL
2872                                 : ( ( position == 1 )
2873                                     ? TEXT_POSITION_SUPERSCRIPT
2874                                     : TEXT_POSITION_SUBSCRIPT );
2875                         fmt.cs.text_position = TRUE;
2876                         fmt.font_size = oldfmt.font_size;
2877                 }
2878                 if (color_set) {
2879                         fmt.color = *color;
2880                         fmt.cs.color = TRUE;
2881                 }
2882                 if (font_set) {
2883                         fmt.font = wp_get_font_index(font_name,
2884                                                      DEFAULT_FONT);
2885                         fmt.cs.font = TRUE;
2886                 }
2887                 g_free(font_name);
2888                 if (font_size_set) {
2889                         fmt.cs.font_size = TRUE;
2890                         fmt.font_size = wp_get_font_size_index(font_size, DEFAULT_FONT_SIZE);
2891                 }
2892                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2893                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), window);
2894         }
2895         gtk_widget_destroy (dialog);
2896         
2897         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2898 }
2899
2900 void
2901 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2902 {
2903         ModestMsgEditWindowPrivate *priv;
2904
2905         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2906         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2907         
2908         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2909
2910         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2911         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2912 }
2913
2914 void
2915 modest_msg_edit_window_redo (ModestMsgEditWindow *window)
2916 {
2917         ModestMsgEditWindowPrivate *priv;
2918
2919         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2920         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2921         
2922         wp_text_buffer_redo (WP_TEXT_BUFFER (priv->text_buffer));
2923
2924         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
2925         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
2926
2927 }
2928
2929 static void  
2930 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2931 {
2932         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2933
2934         priv->can_undo = can_undo;
2935 }
2936
2937 static void  
2938 text_buffer_can_redo (GtkTextBuffer *buffer, gboolean can_redo, ModestMsgEditWindow *window)
2939 {
2940         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2941
2942         priv->can_redo = can_redo;
2943 }
2944
2945 gboolean            
2946 modest_msg_edit_window_can_undo (ModestMsgEditWindow *window)
2947 {
2948         ModestMsgEditWindowPrivate *priv;
2949         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2950         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2951
2952         return priv->can_undo;
2953 }
2954
2955 gboolean            
2956 modest_msg_edit_window_can_redo (ModestMsgEditWindow *window)
2957 {
2958         ModestMsgEditWindowPrivate *priv;
2959         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2960         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2961
2962         return priv->can_redo;
2963 }
2964
2965
2966 static void
2967 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2968 {
2969         GtkTextIter iter;
2970         GtkTextIter match_start, match_end;
2971
2972         if (image_id == NULL)
2973                 return;
2974
2975         gtk_text_buffer_get_start_iter (buffer, &iter);
2976
2977         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2978                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2979                 GSList *node;
2980                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2981                         GtkTextTag *tag = (GtkTextTag *) node->data;
2982                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2983                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2984                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2985                                         gint offset;
2986                                         offset = gtk_text_iter_get_offset (&match_start);
2987                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2988                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2989                                 }
2990                         }
2991                 }
2992                 gtk_text_iter_forward_char (&iter);
2993         }
2994 }
2995
2996 gboolean
2997 message_is_empty (ModestMsgEditWindow *window)
2998 {
2999         ModestMsgEditWindowPrivate *priv = NULL;
3000
3001         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3002         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3003
3004         /** TODO: Add wpeditor API to tell us if there is any _visible_ text,
3005          * so we can ignore markup.
3006          */
3007         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
3008         gint count = 0;
3009         if (buf)
3010                 count = gtk_text_buffer_get_char_count (buf);
3011
3012         return count == 0;
3013 }
3014
3015 static gboolean
3016 msg_body_focus (GtkWidget *focus,
3017                 GdkEventFocus *event,
3018                 gpointer userdata)
3019 {
3020         
3021         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (userdata));
3022         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (userdata));
3023         modest_window_check_dimming_rules_group (MODEST_WINDOW (userdata), MODEST_DIMMING_RULES_CLIPBOARD);
3024         return FALSE;
3025 }
3026
3027 static void
3028 recpt_field_changed (GtkTextBuffer *buffer,
3029                   ModestMsgEditWindow *editor)
3030 {
3031         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3032         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3033 }
3034
3035 static void
3036 body_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor)
3037 {
3038         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (editor));
3039         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (editor));
3040 }
3041
3042 void
3043 modest_msg_edit_window_set_modified (ModestMsgEditWindow *editor,
3044                                      gboolean modified)
3045 {
3046         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3047         GtkTextBuffer *buffer;
3048
3049         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3050         gtk_text_buffer_set_modified (buffer, modified);
3051         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3052         gtk_text_buffer_set_modified (buffer, modified);
3053         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3054         gtk_text_buffer_set_modified (buffer, modified);
3055         gtk_text_buffer_set_modified (priv->text_buffer, modified);
3056 }
3057
3058 gboolean
3059 modest_msg_edit_window_is_modified (ModestMsgEditWindow *editor)
3060 {
3061         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
3062         const char *account_name;
3063         GtkTextBuffer *buffer;
3064
3065         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
3066         if (gtk_text_buffer_get_modified (buffer))
3067                 return TRUE;
3068         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
3069         if (gtk_text_buffer_get_modified (buffer))
3070                 return TRUE;
3071         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
3072         if (gtk_text_buffer_get_modified (buffer))
3073                 return TRUE;
3074         if (gtk_text_buffer_get_modified (priv->text_buffer))
3075                 return TRUE;
3076         account_name = modest_selector_picker_get_active_id (MODEST_SELECTOR_PICKER (priv->from_field));
3077         if (!priv->original_account_name || strcmp(account_name, priv->original_account_name)) {
3078                 return TRUE;
3079         }
3080
3081         return FALSE;
3082 }
3083
3084
3085
3086
3087 gboolean
3088 modest_msg_edit_window_check_names (ModestMsgEditWindow *window, gboolean add_to_addressbook)
3089 {
3090         ModestMsgEditWindowPrivate *priv = NULL;
3091         
3092         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3093         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3094
3095         /* check if there's no recipient added */
3096         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
3097             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
3098             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
3099                 /* no recipient contents, then select contacts */
3100                 modest_msg_edit_window_open_addressbook (window, NULL);
3101                 return FALSE;
3102         }
3103
3104         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field),  add_to_addressbook)) {
3105                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3106                 return FALSE;
3107         }
3108         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field),  add_to_addressbook)) {
3109                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->cc_field));
3110                 return FALSE;
3111         }
3112         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field), add_to_addressbook)) {
3113                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->bcc_field));
3114                 return FALSE;
3115         }
3116
3117         if (!modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->cc_field)) &&
3118             !modest_recpt_editor_has_focus (MODEST_RECPT_EDITOR (priv->bcc_field)))
3119                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
3120
3121         return TRUE;
3122
3123 }
3124
3125 static void
3126 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
3127                                                ModestMsgEditWindow *window)
3128 {
3129         modest_msg_edit_window_offer_attach_file (window);
3130 }
3131
3132 const gchar *
3133 modest_msg_edit_window_get_clipboard_text (ModestMsgEditWindow *win)
3134 {
3135         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3136
3137         return priv->clipboard_text;
3138 }
3139
3140 static void
3141 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
3142                                                GdkEvent *event,
3143                                                ModestMsgEditWindow *window)
3144 {
3145         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3146         GtkClipboard *selection_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3147         gchar *text = NULL;
3148         if (!GTK_WIDGET_VISIBLE (window))
3149                 return;
3150
3151         g_object_ref (window);
3152         text = gtk_clipboard_wait_for_text (selection_clipboard);
3153
3154         if (priv->clipboard_text != NULL) {
3155                 g_free (priv->clipboard_text);
3156         }
3157         priv->clipboard_text = text;
3158
3159         if (GTK_WIDGET_VISIBLE (window)) {
3160                 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3161         }
3162         g_object_unref (window);
3163 }
3164
3165 static gboolean clipboard_owner_change_idle (gpointer userdata)
3166 {
3167         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
3168         ModestMsgEditWindowPrivate *priv;
3169
3170         gdk_threads_enter ();
3171         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
3172         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3173
3174         priv->clipboard_owner_idle = 0;
3175         modest_msg_edit_window_clipboard_owner_change (NULL, NULL, window);
3176         gdk_threads_leave ();
3177
3178         return FALSE;
3179 }
3180
3181 static void
3182 modest_msg_edit_window_clipboard_owner_handle_change_in_idle (ModestMsgEditWindow *window)
3183 {
3184         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3185         if (priv->clipboard_owner_idle == 0) {
3186                 priv->clipboard_owner_idle = g_idle_add (clipboard_owner_change_idle, window);
3187         }
3188 }
3189
3190 static void 
3191 subject_field_move_cursor (GtkEntry *entry,
3192                            GtkMovementStep step,
3193                            gint a1,
3194                            gboolean a2,
3195                            gpointer window)
3196 {
3197         if (!GTK_WIDGET_VISIBLE (window))
3198                 return;
3199
3200         modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
3201 }
3202
3203 static void 
3204 update_window_title (ModestMsgEditWindow *window)
3205 {
3206         ModestMsgEditWindowPrivate *priv = NULL;
3207         const gchar *subject;
3208
3209         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3210         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
3211         if (subject == NULL || subject[0] == '\0')
3212                 subject = _("mail_va_new_email");
3213
3214         gtk_window_set_title (GTK_WINDOW (window), subject);
3215
3216 }
3217
3218 static void  
3219 subject_field_changed (GtkEditable *editable, 
3220                        ModestMsgEditWindow *window)
3221 {
3222         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3223         update_window_title (window);
3224         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3225         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
3226         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
3227 }
3228
3229 static void  
3230 subject_field_insert_text (GtkEditable *editable, 
3231                            gchar *new_text,
3232                            gint new_text_length,
3233                            gint *position,
3234                            ModestMsgEditWindow *window)
3235 {
3236         GString *result = g_string_new ("");
3237         gchar *current;
3238         gint result_len = 0;
3239         const gchar *entry_text = NULL;
3240         gint old_length;
3241
3242         entry_text = gtk_entry_get_text (GTK_ENTRY (editable));
3243         old_length = g_utf8_strlen (entry_text, -1);
3244
3245         for (current = new_text; current != NULL && *current != '\0'; current = g_utf8_next_char (current)) {
3246                 gunichar c = g_utf8_get_char_validated (current, 8);
3247                 /* Invalid unichar, stop */
3248                 if (c == -1)
3249                         break;
3250                 /* a bullet */
3251                 if (c == 0x2022)
3252                         continue;
3253                 result = g_string_append_unichar (result, c);
3254                 result_len++;
3255         }
3256
3257         if (MIN (result_len, 1000) != g_utf8_strlen (new_text, 1000)) {
3258                 g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
3259                 if (result_len > 0)
3260                 {
3261                         /* Prevent endless recursion */
3262                         g_signal_handlers_block_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3263                         g_signal_emit_by_name (editable, "insert-text", 
3264                                                (gpointer) result->str, (gpointer) result->len,
3265                                                (gpointer) position, (gpointer) window);
3266                        g_signal_handlers_unblock_by_func(G_OBJECT(editable), G_CALLBACK(subject_field_insert_text), window);
3267                 }
3268         }
3269
3270         if (result_len + old_length > 1000) {
3271                 hildon_banner_show_information (GTK_WIDGET (window), NULL, 
3272                                                 dgettext("hildon-common-strings",
3273                                                          "ckdg_ib_maximum_characters_reached"));
3274         }
3275         g_string_free (result, TRUE);
3276 }
3277
3278 void
3279 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
3280                                             gboolean show)
3281 {
3282         ModestMsgEditWindowPrivate *priv = NULL;
3283
3284         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3285         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3286
3287         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
3288
3289         if (show) {
3290                 gtk_widget_show_all (priv->find_toolbar);
3291                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
3292         } else {
3293                 gtk_widget_hide_all (priv->find_toolbar);
3294                 gtk_widget_grab_focus (priv->msg_body);
3295         }
3296 }
3297
3298 static gboolean 
3299 gtk_text_iter_forward_search_insensitive (const GtkTextIter *iter,
3300                                           const gchar *str,
3301                                           GtkTextIter *match_start,
3302                                           GtkTextIter *match_end)
3303 {
3304         GtkTextIter end_iter;
3305         gchar *str_casefold;
3306         gint str_chars_n;
3307         gchar *range_text;
3308         gchar *range_casefold;
3309         gint offset;
3310         gint range_chars_n;
3311         gboolean result = FALSE;
3312
3313         if (str == NULL)
3314                 return TRUE;
3315         
3316         /* get end iter */
3317         end_iter = *iter;
3318         gtk_text_iter_forward_to_end (&end_iter);
3319
3320         str_casefold = g_utf8_casefold (str, -1);
3321         str_chars_n = strlen (str);
3322
3323         range_text = gtk_text_iter_get_visible_text (iter, &end_iter);
3324         range_casefold = g_utf8_casefold (range_text, -1);
3325         range_chars_n = strlen (range_casefold);
3326
3327         if (range_chars_n < str_chars_n) {
3328                 g_free (str_casefold);
3329                 g_free (range_text);
3330                 g_free (range_casefold);
3331                 return FALSE;
3332         }
3333
3334         for (offset = 0; offset <= range_chars_n - str_chars_n; offset++) {
3335                 gchar *range_subtext = g_strndup (range_casefold + offset, str_chars_n);
3336                 if (!g_utf8_collate (range_subtext, str_casefold)) {
3337                         gchar *found_text = g_strndup (range_text + offset, str_chars_n);
3338                         result = TRUE;
3339                         gtk_text_iter_forward_search (iter, found_text, GTK_TEXT_SEARCH_VISIBLE_ONLY|GTK_TEXT_SEARCH_TEXT_ONLY,
3340                                                       match_start, match_end, NULL);
3341                         g_free (found_text);
3342                 }
3343                 g_free (range_subtext);
3344                 if (result)
3345                         break;
3346         }
3347         g_free (str_casefold);
3348         g_free (range_text);
3349         g_free (range_casefold);
3350
3351         return result;
3352 }
3353
3354
3355 static void 
3356 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
3357                                             ModestMsgEditWindow *window)
3358 {
3359         gchar *current_search = NULL;
3360         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3361         gboolean result;
3362         GtkTextIter selection_start, selection_end;
3363         GtkTextIter match_start, match_end;
3364         gboolean continue_search = FALSE;
3365
3366         if (message_is_empty (window)) {
3367                 g_free (priv->last_search);
3368                 priv->last_search = NULL;
3369                 hildon_banner_show_information (GTK_WIDGET (window), NULL, _("mail_ib_nothing_to_find"));
3370                 return;
3371         }
3372
3373         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
3374         if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
3375                 g_free (current_search);
3376                 g_free (priv->last_search);
3377                 priv->last_search = NULL;
3378                 /* Information banner about empty search */
3379                 hildon_banner_show_information (NULL, NULL, dgettext ("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
3380                 return;
3381         }
3382
3383         if ((priv->last_search != NULL)&&(!strcmp (current_search, priv->last_search))) {
3384                 continue_search = TRUE;
3385         } else {
3386                 g_free (priv->last_search);
3387                 priv->last_search = g_strdup (current_search);
3388         }
3389
3390         if (continue_search) {
3391                 gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
3392                 result = gtk_text_iter_forward_search_insensitive (&selection_end, current_search, 
3393                                                                    &match_start, &match_end);
3394                 if (!result)
3395                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_search_complete"));
3396         } else {
3397                 GtkTextIter buffer_start;
3398                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
3399                 result = gtk_text_iter_forward_search_insensitive (&buffer_start, current_search, 
3400                                                                    &match_start, &match_end);
3401                 if (!result)
3402                         hildon_banner_show_information (NULL, NULL, dgettext ("hildon-libs", "ckct_ib_find_no_matches"));
3403         }
3404
3405         /* Mark as selected the string found in search */
3406         if (result) {
3407                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
3408                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
3409                 correct_scroll_without_drag_check (MODEST_MSG_EDIT_WINDOW (window), FALSE);
3410         } else {
3411                 g_free (priv->last_search);
3412                 priv->last_search = NULL;
3413         }
3414         g_free (current_search);
3415 }
3416
3417 gboolean 
3418 modest_msg_edit_window_get_sent (ModestMsgEditWindow *window)
3419 {
3420         ModestMsgEditWindowPrivate *priv;
3421
3422         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3423         return priv->sent;
3424 }
3425
3426 void 
3427 modest_msg_edit_window_set_sent (ModestMsgEditWindow *window, 
3428                                  gboolean sent)
3429 {
3430         ModestMsgEditWindowPrivate *priv;
3431
3432         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(window);
3433         priv->sent = sent;
3434 }
3435
3436 static void
3437 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
3438                                           ModestMsgEditWindow *window)
3439 {
3440         modest_msg_edit_window_toggle_find_toolbar (window, FALSE);
3441 }
3442
3443 void
3444 modest_msg_edit_window_set_draft (ModestMsgEditWindow *window,
3445                                   TnyMsg *draft)
3446 {
3447         ModestMsgEditWindowPrivate *priv;
3448         TnyHeader *header = NULL;
3449
3450         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3451         g_return_if_fail ((draft == NULL)||(TNY_IS_MSG (draft)));
3452
3453         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3454         ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
3455
3456         if (priv->draft_msg != NULL) {
3457                 g_object_unref (priv->draft_msg);
3458         }
3459
3460         if (draft != NULL) {
3461                 g_object_ref (draft);
3462                 header = tny_msg_get_header (draft);
3463                 if (priv->msg_uid) {
3464                         g_free (priv->msg_uid);
3465                         priv->msg_uid = NULL;
3466                 }
3467                 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
3468                 if (GTK_WIDGET_REALIZED (window)) {
3469                         if (!modest_window_mgr_register_window (mgr, MODEST_WINDOW (window), NULL)) {
3470                                 gtk_widget_destroy (GTK_WIDGET (window));
3471                                 return;
3472                         }
3473                 }
3474         }
3475
3476         priv->draft_msg = draft;
3477 }
3478
3479 static void  
3480 text_buffer_apply_tag (GtkTextBuffer *buffer, GtkTextTag *tag, 
3481                        GtkTextIter *start, GtkTextIter *end,
3482                        gpointer userdata)
3483 {
3484         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
3485         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (userdata);
3486         gchar *tag_name;
3487
3488         if (tag == NULL) return;
3489         g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
3490         if ((tag_name != NULL) && (g_str_has_prefix (tag_name, "image-tag-replace-"))) {
3491                 replace_with_images (window, priv->images);
3492         }
3493 }
3494
3495 void                    
3496 modest_msg_edit_window_add_part (ModestMsgEditWindow *window,
3497                                  TnyMimePart *part)
3498 {
3499         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3500
3501         g_return_if_fail (TNY_IS_MIME_PART (part));
3502         tny_list_prepend (priv->attachments, (GObject *) part);
3503         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), part, TRUE, 0);
3504         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
3505         gtk_widget_show_all (priv->attachments_caption);
3506         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
3507 }
3508
3509 const gchar*    
3510 modest_msg_edit_window_get_message_uid (ModestMsgEditWindow *window)
3511 {
3512         ModestMsgEditWindowPrivate *priv;
3513
3514         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), NULL);        
3515         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3516
3517         return priv->msg_uid;
3518 }
3519
3520 GtkWidget *
3521 modest_msg_edit_window_get_child_widget (ModestMsgEditWindow *win,
3522                                          ModestMsgEditWindowWidgetType widget_type)
3523 {
3524         ModestMsgEditWindowPrivate *priv;
3525
3526         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (win), NULL);
3527         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (win);
3528
3529         switch (widget_type) {
3530         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BODY:
3531                 return priv->msg_body;
3532                 break;
3533         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_TO:
3534                 return priv->to_field;
3535                 break;
3536         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_CC:
3537                 return priv->cc_field;
3538                 break;
3539         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_BCC:
3540                 return priv->bcc_field;
3541                 break;
3542         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_SUBJECT:
3543                 return priv->subject_field;
3544                 break;
3545         case MODEST_MSG_EDIT_WINDOW_WIDGET_TYPE_ATTACHMENTS:
3546                 return priv->attachments_view;
3547                 break;
3548         default:
3549                 return NULL;
3550         }
3551 }
3552
3553 static void 
3554 remove_tags (WPTextBuffer *buffer)
3555 {
3556         GtkTextIter start, end;
3557
3558         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start);
3559         gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end);
3560
3561         gtk_text_buffer_remove_all_tags (GTK_TEXT_BUFFER (buffer), &start, &end);
3562 }
3563
3564 static void
3565 on_account_removed (TnyAccountStore *account_store, 
3566                     TnyAccount *account,
3567                     gpointer user_data)
3568 {
3569         /* Do nothing if it's a store account, because we use the
3570            transport to send the messages */
3571         if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_TRANSPORT) {
3572                 const gchar *parent_acc = NULL;
3573                 const gchar *our_acc = NULL;
3574
3575                 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
3576                 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
3577                 /* Close this window if I'm showing a message of the removed account */
3578                 if (strcmp (parent_acc, our_acc) == 0)
3579                         modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
3580         }
3581 }
3582
3583 typedef struct _MessageSettingsHelper {
3584         ModestMsgEditWindow *window;
3585         GSList *priority_group;
3586         GtkWidget *align_picker;
3587 } MessageSettingsHelper;
3588
3589 static void
3590 on_priority_toggle (HildonCheckButton *button, 
3591                     MessageSettingsHelper *helper)
3592 {
3593         GSList *node;
3594         ModestMsgEditWindowPrivate *priv;
3595
3596         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (helper->window);
3597         if (hildon_check_button_get_active (button)) {
3598
3599                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3600                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3601                         if ((node_button != button) &&
3602                             hildon_check_button_get_active (node_button)) {
3603                                 hildon_check_button_set_active (node_button, FALSE);
3604                         }
3605                         if (priv->priority_flags != (TnyHeaderFlags) g_object_get_data (G_OBJECT (button), "priority"))
3606                                 modest_msg_edit_window_set_priority_flags (helper->window,
3607                                                                            (TnyHeaderFlags) 
3608                                                                            g_object_get_data (G_OBJECT (button), 
3609                                                                                               "priority"));
3610                 }
3611
3612                 
3613         } else {
3614                 gboolean found = FALSE;
3615                 /* If no one is active, activate it again */
3616                 for (node = helper->priority_group; node != NULL; node = g_slist_next (node)) {
3617                         HildonCheckButton *node_button = (HildonCheckButton *) node->data;
3618                         if (hildon_check_button_get_active (node_button)) {
3619                                 found = TRUE;
3620                                 break;
3621                         }
3622                 }
3623                 if (!found) {
3624                         hildon_check_button_set_active (button, TRUE);
3625                 }
3626         }
3627 }
3628
3629 static void
3630 on_format_picker_value_changed (HildonPickerButton *button,
3631                                 MessageSettingsHelper *helper)
3632 {
3633         ModestMsgEditFormat new_format, old_format;
3634         gint file_format;
3635
3636         switch (hildon_picker_button_get_active (button)) {
3637         case 1:
3638                 new_format = MODEST_MSG_EDIT_FORMAT_HTML;
3639                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
3640                 break;
3641         case 0:
3642         default:
3643                 new_format = MODEST_MSG_EDIT_FORMAT_TEXT;
3644                 file_format = MODEST_FILE_FORMAT_PLAIN_TEXT;
3645                 break;
3646         }
3647
3648         old_format = modest_msg_edit_window_get_format (helper->window);
3649         if (new_format != old_format) {
3650                 modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (helper->window), file_format);
3651
3652                 switch (modest_msg_edit_window_get_format (helper->window)) {
3653                 case MODEST_MSG_EDIT_FORMAT_TEXT:
3654                         hildon_picker_button_set_active (button, 0);
3655                         gtk_widget_set_sensitive (helper->align_picker, FALSE);
3656                         break;
3657                 case MODEST_MSG_EDIT_FORMAT_HTML:
3658                 default:
3659                         hildon_picker_button_set_active (button, 1);
3660                         gtk_widget_set_sensitive (helper->align_picker, TRUE);
3661                         break;
3662                 }
3663         }
3664 }
3665
3666 static void
3667 on_align_picker_value_changed (HildonPickerButton *button,
3668                                 MessageSettingsHelper *helper)
3669 {
3670         GtkJustification new_justify;
3671         ModestMsgEditFormatState *format_state = NULL;
3672
3673         switch (hildon_picker_button_get_active (button)) {
3674         case 1:
3675                 new_justify = GTK_JUSTIFY_CENTER;
3676                 break;
3677         case 2:
3678                 new_justify = GTK_JUSTIFY_RIGHT;
3679                 break;
3680         case 0:
3681         default:
3682                 new_justify = GTK_JUSTIFY_LEFT;
3683                 break;
3684         }
3685
3686         format_state = modest_msg_edit_window_get_format_state (helper->window);
3687         if (format_state->justification != new_justify)
3688                 format_state->justification = new_justify;
3689         modest_msg_edit_window_set_format_state (helper->window, format_state);
3690         g_free (format_state);
3691 }
3692
3693 static void
3694 modest_msg_edit_window_show_msg_settings_dialog (ModestMsgEditWindow *window)
3695 {
3696         GtkWidget *dialog;
3697         GtkWidget *vbox;
3698         GtkWidget *priority_hbox;
3699         GtkWidget *high_toggle, *medium_toggle, *low_toggle;
3700         GtkWidget *captioned;
3701         GtkSizeGroup *title_sizegroup, *value_sizegroup;
3702         GtkWidget *format_picker;
3703         GtkWidget *format_selector;
3704         ModestMsgEditWindowPrivate *priv;
3705         MessageSettingsHelper helper = {0,};
3706         ModestMsgEditFormatState *format_state = NULL;
3707
3708         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
3709         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
3710         helper.window = window;
3711         helper.priority_group = NULL;
3712
3713         title_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3714         value_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3715
3716         dialog = gtk_dialog_new ();
3717         vbox = gtk_vbox_new (FALSE, 0);
3718         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
3719         gtk_widget_show (vbox);
3720
3721         /* Priority toggles */
3722         priority_hbox = gtk_hbox_new (TRUE, 0);
3723         high_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3724         gtk_button_set_label (GTK_BUTTON (high_toggle), _("mcen_me_editor_priority_high"));
3725         helper.priority_group = g_slist_prepend (helper.priority_group, high_toggle);
3726         g_object_set_data (G_OBJECT (high_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_HIGH_PRIORITY));
3727         medium_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3728         gtk_button_set_label (GTK_BUTTON (medium_toggle), _("mcen_me_editor_priority_normal"));
3729         helper.priority_group = g_slist_prepend (helper.priority_group, medium_toggle);
3730         g_object_set_data (G_OBJECT (medium_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_NORMAL_PRIORITY));
3731         low_toggle = hildon_check_button_new (HILDON_SIZE_FINGER_HEIGHT);
3732         gtk_button_set_label (GTK_BUTTON (low_toggle), _("mcen_me_editor_priority_low"));
3733         helper.priority_group = g_slist_prepend (helper.priority_group, low_toggle);
3734         g_object_set_data (G_OBJECT (low_toggle), "priority", GINT_TO_POINTER (TNY_HEADER_FLAG_LOW_PRIORITY));
3735         gtk_box_pack_start (GTK_BOX (priority_hbox), low_toggle, FALSE, FALSE, 0);
3736         gtk_box_pack_start (GTK_BOX (priority_hbox), medium_toggle, FALSE, FALSE, 0);
3737         gtk_box_pack_start (GTK_BOX (priority_hbox), high_toggle, FALSE, FALSE, 0);
3738         gtk_widget_show_all (priority_hbox);
3739         captioned = modest_maemo_utils_create_captioned (title_sizegroup, value_sizegroup,
3740                                                          _("mcen_me_editor_message_priority"), priority_hbox);
3741         gtk_widget_show (captioned);
3742         gtk_box_pack_start (GTK_BOX (vbox), captioned, FALSE, FALSE, 0);
3743
3744         /* format selector */
3745         format_selector = hildon_touch_selector_new_text ();
3746         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_plain_text"));
3747         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (format_selector), _("mcen_me_editor_formatted_text"));
3748         format_picker = hildon_picker_button_new (MODEST_EDITABLE_SIZE,
3749                                                   HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
3750         hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (format_picker), HILDON_TOUCH_SELECTOR (format_selector));
3751         modest_maemo_utils_set_hbutton_layout (title_sizegroup, value_sizegroup,
3752                                                _("mcen_me_editor_format"), format_picker);
3753         gtk_widget_show_all (format_picker);
3754         gtk_box_pack_start (GTK_BOX (vbox), format_picker, FALSE, FALSE, 0);
3755
3756
3757         g_object_unref (title_sizegroup);
3758         g_object_unref (value_sizegroup);
3759         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_me_message_settings"));
3760
3761         /* Set current values */
3762         switch (priv->priority_flags) {
3763         case TNY_HEADER_FLAG_HIGH_PRIORITY:
3764                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (high_toggle), TRUE);
3765                 break;
3766         case TNY_HEADER_FLAG_LOW_PRIORITY:
3767                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (low_toggle), TRUE);
3768                 break;
3769         default:
3770                 hildon_check_button_set_active (HILDON_CHECK_BUTTON (medium_toggle), TRUE);
3771                 break;
3772         }
3773
3774         switch (modest_msg_edit_window_get_format (window)) {
3775         case MODEST_MSG_EDIT_FORMAT_TEXT:
3776                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 0);
3777                 gtk_widget_set_sensitive (helper.align_picker, FALSE);
3778                 break;
3779         case MODEST_MSG_EDIT_FORMAT_HTML:
3780         default:
3781                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (format_picker), 1);
3782                 gtk_widget_set_sensitive (helper.align_picker, TRUE);
3783                 break;
3784         }
3785
3786         format_state = modest_msg_edit_window_get_format_state (window);
3787         switch (format_state->justification) {
3788         case GTK_JUSTIFY_RIGHT:
3789                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 2);
3790                 break;
3791         case GTK_JUSTIFY_CENTER:
3792                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 1);
3793                 break;
3794         default:
3795                 hildon_picker_button_set_active (HILDON_PICKER_BUTTON (helper.align_picker), 0);
3796                 break;
3797         
3798         }
3799         g_free (format_state);
3800
3801         /* Signal connects */
3802         g_signal_connect (G_OBJECT (high_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3803         g_signal_connect (G_OBJECT (medium_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3804         g_signal_connect (G_OBJECT (low_toggle), "toggled", G_CALLBACK (on_priority_toggle), &helper);
3805         g_signal_connect (G_OBJECT (format_picker), "value-changed", G_CALLBACK (on_format_picker_value_changed), &helper);
3806         g_signal_connect (G_OBJECT (helper.align_picker), "value-changed", 
3807                           G_CALLBACK (on_align_picker_value_changed), &helper);
3808         
3809         gtk_dialog_run (GTK_DIALOG (dialog));
3810         
3811         /* Read new values */
3812         
3813         gtk_widget_destroy (dialog);
3814         g_slist_free (helper.priority_group);
3815         
3816 }
3817
3818 static void on_message_settings (GtkAction *action,
3819                                  ModestMsgEditWindow *window)
3820 {
3821         modest_msg_edit_window_show_msg_settings_dialog (window);
3822 }
3823
3824 static void
3825 on_cc_button_toggled (HildonCheckButton *button,
3826                       ModestMsgEditWindow *window)
3827 {
3828         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3829
3830         modest_msg_edit_window_show_cc (MODEST_MSG_EDIT_WINDOW (window),
3831                                         hildon_check_button_get_active (button));
3832 }
3833
3834 static void
3835 on_bcc_button_toggled (HildonCheckButton *button,
3836                       ModestMsgEditWindow *window)
3837 {
3838         g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window));
3839
3840         modest_msg_edit_window_show_bcc (MODEST_MSG_EDIT_WINDOW (window),
3841                                         hildon_check_button_get_active (button));
3842 }
3843
3844 static void 
3845 setup_menu (ModestMsgEditWindow *self)
3846 {
3847         ModestMsgEditWindowPrivate *priv = NULL;
3848
3849         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(self));
3850
3851         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
3852
3853         /* Settings menu buttons */
3854         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_checknames"), NULL,
3855                                            APP_MENU_CALLBACK (modest_ui_actions_on_check_names),
3856                                            NULL);
3857         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_undo"), "<Ctrl>z",
3858                                            APP_MENU_CALLBACK (modest_ui_actions_on_undo),
3859                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_undo));
3860
3861         priv->cc_button = hildon_check_button_new (0);
3862         gtk_button_set_label (GTK_BUTTON (priv->cc_button), _("mcen_me_editor_showcc"));
3863         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->cc_button),
3864                                         FALSE);
3865         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->cc_button),
3866                                                   NULL);
3867         g_signal_connect (G_OBJECT (priv->cc_button), "toggled",
3868                           G_CALLBACK (on_cc_button_toggled), (gpointer) self);
3869         priv->bcc_button = hildon_check_button_new (0);
3870         gtk_button_set_label (GTK_BUTTON (priv->bcc_button), _("mcen_me_editor_showbcc"));
3871         hildon_check_button_set_active (HILDON_CHECK_BUTTON (priv->bcc_button),
3872                                         FALSE);
3873         modest_hildon2_window_add_button_to_menu (MODEST_HILDON2_WINDOW (self), GTK_BUTTON (priv->bcc_button),
3874                                                   NULL);
3875         g_signal_connect (G_OBJECT (priv->bcc_button), "toggled",
3876                           G_CALLBACK (on_bcc_button_toggled), (gpointer) self);
3877
3878         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_editor_attach_inlineimage"), NULL,
3879                                            APP_MENU_CALLBACK (modest_ui_actions_on_insert_image),
3880                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_set_style));
3881         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3882                                            APP_MENU_CALLBACK (modest_ui_actions_on_remove_attachments),
3883                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_editor_remove_attachment));
3884         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_message_settings"), NULL,
3885                                            APP_MENU_CALLBACK (on_message_settings),
3886                                            NULL);
3887         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), "<Ctrl>f",
3888                                            APP_MENU_CALLBACK (modest_ui_actions_on_toggle_find_in_page),
3889                                            NULL);
3890 }
3891