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