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