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