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