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