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