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