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