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