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