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