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