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