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