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