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