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