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