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