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