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