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