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