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