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