2007-06-22 Murray Cumming <murrayc@murrayc.com>
[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-address-book.h"
59 #include "modest-text-utils.h"
60 #include <tny-simple-list.h>
61 #include <wptextview.h>
62 #include <wptextbuffer.h>
63 #include "modest-scroll-area.h"
64
65 #include "modest-hildon-includes.h"
66 #include "widgets/modest-msg-edit-window-ui.h"
67 #include <libgnomevfs/gnome-vfs-mime.h>
68 #include "modest-maemo-utils.h"
69
70
71 #define DEFAULT_FONT_SIZE 3
72 #define DEFAULT_FONT 2
73 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
74 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
75 #define DEFAULT_MAIN_VBOX_SPACING 6
76 #define SUBJECT_MAX_LENGTH 1000
77 #define IMAGE_MAX_WIDTH 640
78
79 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
80 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
81 static void  modest_msg_edit_window_finalize     (GObject *obj);
82
83 static gboolean msg_body_focus (GtkWidget *focus, GdkEventFocus *event, gpointer userdata);
84 static void  recpt_field_changed (GtkTextBuffer *buffer, ModestMsgEditWindow *editor);
85 static void  send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
86 static void  style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
87 static void  remove_attachment_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
88 static void  zoom_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor);
89 static void  setup_insensitive_handlers (ModestMsgEditWindow *editor);
90 static void  reset_modified (ModestMsgEditWindow *editor);
91 static gboolean is_modified (ModestMsgEditWindow *editor);
92
93 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
94 static void  text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata);
95 static void  text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window);
96 static void  text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id);
97 static void  subject_field_changed (GtkEditable *editable, ModestMsgEditWindow *window);
98 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
99                                                          gpointer userdata);
100 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
101                                                  gpointer userdata);
102 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
103                                                  gpointer userdata);
104 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
105 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
106                                                            GdkEventWindowState *event, 
107                                                            gpointer userdata);
108 static void modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
109                                                      ModestRecptEditor *editor);
110 static void modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
111                                                            ModestMsgEditWindow *window);
112
113 /* ModestWindow methods implementation */
114 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
115 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
116 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
117 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
118 static void modest_msg_edit_window_show_toolbar   (ModestWindow *window,
119                                                    gboolean show_toolbar);
120 static void modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
121                                                            GdkEvent *event,
122                                                            ModestMsgEditWindow *window);
123 static void modest_msg_edit_window_system_clipboard_owner_change (GtkClipboard *clipboard,
124                                                                   GdkEvent *event,
125                                                                   ModestMsgEditWindow *window);
126 static void update_window_title (ModestMsgEditWindow *window);
127 static void update_dimmed (ModestMsgEditWindow *window);
128 static void update_paste_dimming (ModestMsgEditWindow *window);
129 static void update_select_all_dimming (ModestMsgEditWindow *window);
130 static void update_zoom_dimming (ModestMsgEditWindow *window);
131
132 /* Find toolbar */
133 static void modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
134                                                         ModestMsgEditWindow *window);
135 static void modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
136                                                        ModestMsgEditWindow *window);
137 static void edit_menu_activated (GtkAction *action,
138                                  gpointer userdata);
139 static void view_menu_activated (GtkAction *action,
140                                  gpointer userdata);
141
142 /* list my signals */
143 enum {
144         /* MY_SIGNAL_1, */
145         /* MY_SIGNAL_2, */
146         LAST_SIGNAL
147 };
148
149 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
150 struct _ModestMsgEditWindowPrivate {
151         GtkWidget   *msg_body;
152         GtkWidget   *header_box;
153         
154         ModestPairList *from_field_protos;
155         GtkWidget   *from_field;
156         
157         GtkWidget   *to_field;
158         GtkWidget   *cc_field;
159         GtkWidget   *bcc_field;
160         GtkWidget   *subject_field;
161         GtkWidget   *attachments_view;
162         GtkWidget   *priority_icon;
163         GtkWidget   *add_attachment_button;
164
165         GtkWidget   *cc_caption;
166         GtkWidget   *bcc_caption;
167         GtkWidget   *attachments_caption;
168
169         GtkTextBuffer *text_buffer;
170
171         GtkWidget   *font_size_toolitem;
172         GtkWidget   *font_face_toolitem;
173         GtkWidget   *font_color_button;
174         GSList      *font_items_group;
175         GtkWidget   *font_tool_button_label;
176         GSList      *size_items_group;
177         GtkWidget   *size_tool_button_label;
178         
179         GtkWidget   *find_toolbar;
180
181         GtkWidget   *scroll;
182         GtkWidget   *scroll_area;
183
184         gint last_cid;
185         GList *attachments;
186
187         TnyHeaderFlags priority_flags;
188
189         gdouble zoom_level;
190         
191         gulong      clipboard_change_handler_id;
192         gulong      system_clipboard_change_handler_id;
193
194         TnyMsg      *draft_msg;
195 };
196
197 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
198                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
199                                                     ModestMsgEditWindowPrivate))
200 /* globals */
201 static GtkWindowClass *parent_class = NULL;
202
203 /* uncomment the following if you have defined any signals */
204 /* static guint signals[LAST_SIGNAL] = {0}; */
205
206 GType
207 modest_msg_edit_window_get_type (void)
208 {
209         static GType my_type = 0;
210         if (!my_type) {
211                 static const GTypeInfo my_info = {
212                         sizeof(ModestMsgEditWindowClass),
213                         NULL,           /* base init */
214                         NULL,           /* base finalize */
215                         (GClassInitFunc) modest_msg_edit_window_class_init,
216                         NULL,           /* class finalize */
217                         NULL,           /* class data */
218                         sizeof(ModestMsgEditWindow),
219                         1,              /* n_preallocs */
220                         (GInstanceInitFunc) modest_msg_edit_window_init,
221                         NULL
222                 };
223                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
224                                                   "ModestMsgEditWindow",
225                                                   &my_info, 0);
226
227                 wp_text_buffer_library_init ();
228         }
229         return my_type;
230 }
231
232 static void
233 save_state (ModestWindow *self)
234 {
235         modest_widget_memory_save (modest_runtime_get_conf(),
236                                    G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
237 }
238
239
240 static void
241 restore_settings (ModestMsgEditWindow *self)
242 {
243         modest_widget_memory_restore (modest_runtime_get_conf(),
244                                       G_OBJECT(self), MODEST_CONF_EDIT_WINDOW_KEY);
245 }
246
247
248 static void
249 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
250 {
251         GObjectClass *gobject_class;
252         ModestWindowClass *modest_window_class;
253         gobject_class = (GObjectClass*) klass;
254         modest_window_class = (ModestWindowClass*) klass;
255
256         parent_class            = g_type_class_peek_parent (klass);
257         gobject_class->finalize = modest_msg_edit_window_finalize;
258
259         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
260         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
261         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
262         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
263         modest_window_class->show_toolbar_func = modest_msg_edit_window_show_toolbar;
264
265         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
266
267         modest_window_class->save_state_func = save_state;
268 }
269
270 static void
271 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
272 {
273         ModestMsgEditWindowPrivate *priv;
274         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
275
276         priv->msg_body      = NULL;
277         priv->from_field    = NULL;
278         priv->to_field      = NULL;
279         priv->cc_field      = NULL;
280         priv->bcc_field     = NULL;
281         priv->subject_field = NULL;
282         priv->attachments   = NULL;
283         priv->last_cid      = 0;
284         priv->zoom_level    = 1.0;
285
286         priv->cc_caption    = NULL;
287         priv->bcc_caption    = NULL;
288
289         priv->priority_flags = 0;
290
291         priv->find_toolbar = NULL;
292
293         priv->draft_msg = NULL;
294         priv->clipboard_change_handler_id = 0;
295         priv->system_clipboard_change_handler_id = 0;
296 }
297
298
299 /* FIXME: this is a dup from the one in gtk/ */
300
301 /** 
302  * @result: A ModestPairList, which must be freed with modest_pair_list_free().
303  */
304 static ModestPairList*
305 get_transports (void)
306 {
307         GSList *transports = NULL;
308         
309         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
310         GSList *accounts = modest_account_mgr_account_names (account_mgr, 
311                                                              TRUE /* only enabled accounts. */); 
312                                                 
313         GSList *cursor = accounts;
314         while (cursor) {
315                 gchar *account_name = cursor->data;
316                 gchar *from_string  = NULL;
317                 if (account_name) {
318                         from_string = modest_account_mgr_get_from_string (account_mgr,
319                                                                           account_name);
320                 }
321                 
322                 if (from_string && account_name) {
323                         gchar *name = account_name;
324                         ModestPair *pair = modest_pair_new ((gpointer) name,
325                                                 (gpointer) from_string , TRUE);
326                         transports = g_slist_prepend (transports, pair);
327                 }
328                 
329                 cursor = cursor->next;
330         }
331         g_slist_free (accounts); /* only free the accounts, not the elements,
332                                   * because they are used in the pairlist */
333         return transports;
334 }
335
336
337 static void
338 init_window (ModestMsgEditWindow *obj)
339 {
340         GtkWidget *from_caption, *to_caption, *subject_caption;
341         GtkWidget *main_vbox;
342         ModestMsgEditWindowPrivate *priv;
343
344         GtkSizeGroup *size_group;
345         GtkWidget *frame;
346         GtkWidget *subject_box;
347         GtkWidget *attachment_icon;
348         GtkWidget *window_box;
349
350         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
351
352         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
353
354         /* Note: This ModestPairList* must exist for as long as the combo
355          * that uses it, because the ModestComboBox uses the ID opaquely, 
356          * so it can't know how to manage its memory. */ 
357         priv->from_field_protos = get_transports ();
358
359         priv->from_field    = modest_combo_box_new (priv->from_field_protos, g_str_equal);
360
361         priv->to_field      = modest_recpt_editor_new ();
362         priv->cc_field      = modest_recpt_editor_new ();
363         priv->bcc_field     = modest_recpt_editor_new ();
364         subject_box = gtk_hbox_new (FALSE, 0);
365         priv->priority_icon = gtk_image_new ();
366         gtk_box_pack_start (GTK_BOX (subject_box), priv->priority_icon, FALSE, FALSE, 0);
367         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
368         hildon_gtk_entry_set_input_mode (GTK_ENTRY (priv->subject_field), 
369                                          HILDON_GTK_INPUT_MODE_FULL | HILDON_GTK_INPUT_MODE_AUTOCAP);
370         gtk_box_pack_start (GTK_BOX (subject_box), priv->subject_field, TRUE, TRUE, 0);
371         priv->add_attachment_button = gtk_button_new ();
372         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->add_attachment_button), GTK_CAN_FOCUS);
373         gtk_button_set_relief (GTK_BUTTON (priv->add_attachment_button), GTK_RELIEF_NONE);
374         gtk_button_set_focus_on_click (GTK_BUTTON (priv->add_attachment_button), FALSE);
375         gtk_button_set_alignment (GTK_BUTTON (priv->add_attachment_button), 1.0, 1.0);
376         attachment_icon = gtk_image_new_from_icon_name (MODEST_HEADER_ICON_ATTACH, GTK_ICON_SIZE_BUTTON);
377         gtk_container_add (GTK_CONTAINER (priv->add_attachment_button), attachment_icon);
378         gtk_box_pack_start (GTK_BOX (subject_box), priv->add_attachment_button, FALSE, FALSE, 0);
379         priv->attachments_view = modest_attachments_view_new (NULL);
380         
381         priv->header_box = gtk_vbox_new (FALSE, 0);
382         
383         from_caption = hildon_caption_new (size_group, _("mail_va_from"), priv->from_field, NULL, 0);
384         to_caption = hildon_caption_new (size_group, _("mail_va_to"), priv->to_field, NULL, 0);
385         priv->cc_caption = hildon_caption_new (size_group, _("mail_va_cc"), priv->cc_field, NULL, 0);
386         priv->bcc_caption = hildon_caption_new (size_group, _("mail_va_hotfix1"), priv->bcc_field, NULL, 0);
387         subject_caption = hildon_caption_new (size_group, _("mail_va_subject"), subject_box, NULL, 0);
388         priv->attachments_caption = hildon_caption_new (size_group, _("mail_va_attachment"), priv->attachments_view, NULL, 0);
389         g_object_unref (size_group);
390
391         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
392         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
393         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
394         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
395         gtk_size_group_add_widget (size_group, priv->subject_field);
396         gtk_size_group_add_widget (size_group, priv->attachments_view);
397         g_object_unref (size_group);
398
399         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
400         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
401         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
402         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
403         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
404         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->attachments_caption, FALSE, FALSE, 0);
405         gtk_widget_set_no_show_all (priv->attachments_caption, TRUE);
406
407
408         priv->msg_body = wp_text_view_new ();
409         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
410         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
411         g_object_set (priv->text_buffer, "font_scale", 1.0, NULL);
412         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
413 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
414         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
415
416         priv->find_toolbar = hildon_find_toolbar_new (NULL);
417         gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
418
419         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
420                           G_CALLBACK (text_buffer_refresh_attributes), obj);
421         g_signal_connect (G_OBJECT (priv->text_buffer), "delete-range",
422                           G_CALLBACK (text_buffer_delete_range), obj);
423         g_signal_connect (G_OBJECT (priv->text_buffer), "can-undo",
424                           G_CALLBACK (text_buffer_can_undo), obj);
425         g_signal_connect (G_OBJECT (obj), "window-state-event",
426                           G_CALLBACK (modest_msg_edit_window_window_state_event),
427                           NULL);
428         g_signal_connect_swapped (G_OBJECT (priv->to_field), "open-addressbook", 
429                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
430         g_signal_connect_swapped (G_OBJECT (priv->cc_field), "open-addressbook", 
431                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
432         g_signal_connect_swapped (G_OBJECT (priv->bcc_field), "open-addressbook", 
433                                   G_CALLBACK (modest_msg_edit_window_open_addressbook), obj);
434
435         g_signal_connect (G_OBJECT (priv->add_attachment_button), "clicked",
436                           G_CALLBACK (modest_msg_edit_window_add_attachment_clicked), obj);
437
438         g_signal_connect (G_OBJECT (priv->msg_body), "focus-in-event",
439                           G_CALLBACK (msg_body_focus), obj);
440         g_signal_connect (G_OBJECT (priv->msg_body), "focus-out-event",
441                           G_CALLBACK (msg_body_focus), obj);
442         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))),
443                           "changed", G_CALLBACK (recpt_field_changed), obj);
444         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))),
445                           "changed", G_CALLBACK (recpt_field_changed), obj);
446         g_signal_connect (G_OBJECT (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))),
447                           "changed", G_CALLBACK (recpt_field_changed), obj);
448         recpt_field_changed (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field)), MODEST_MSG_EDIT_WINDOW (obj));
449         g_signal_connect (G_OBJECT (priv->subject_field), "changed", G_CALLBACK (subject_field_changed), obj);
450
451         g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_edit_window_find_toolbar_close), obj);
452         g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_edit_window_find_toolbar_search), obj);
453
454         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
455         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
456         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
457         
458         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
459
460         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
461         frame = gtk_frame_new (NULL);
462         gtk_box_pack_start (GTK_BOX(main_vbox), frame, TRUE, TRUE, 0);
463
464         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
465         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
466         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
467         
468         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL)) {
469                 gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
470                 gtk_widget_hide (priv->cc_caption);
471         }
472         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL)) {
473                 gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
474                 gtk_widget_hide (priv->bcc_caption);
475         }
476
477         window_box = gtk_vbox_new (FALSE, 0);
478         gtk_box_pack_start (GTK_BOX (window_box), priv->scroll, TRUE, TRUE, 0);
479         gtk_box_pack_end (GTK_BOX (window_box), priv->find_toolbar, FALSE, FALSE, 0);
480         gtk_container_add (GTK_CONTAINER(obj), window_box);
481         priv->scroll_area = modest_scroll_area_new (priv->scroll, priv->msg_body);
482         gtk_container_add (GTK_CONTAINER (frame), priv->scroll_area);
483         
484         /*
485          TODO: scroll_area was never instantiated.
486          Stop building without warnings-as-errors. murrayc.
487         gtk_container_set_focus_vadjustment (GTK_CONTAINER (scroll_area), 
488                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
489         */
490
491         priv->clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change",
492                                                               G_CALLBACK (modest_msg_edit_window_clipboard_owner_change), obj);
493         priv->system_clipboard_change_handler_id = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)), "owner-change",
494                                                               G_CALLBACK (modest_msg_edit_window_system_clipboard_owner_change), obj);
495 }
496         
497
498
499 static void
500 modest_msg_edit_window_finalize (GObject *obj)
501 {
502         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
503
504         if (priv->clipboard_change_handler_id > 0) {
505                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY), priv->clipboard_change_handler_id);
506                 priv->clipboard_change_handler_id = 0;
507         }
508         
509         if (priv->system_clipboard_change_handler_id > 0) {
510                 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 
511                                              priv->system_clipboard_change_handler_id);
512                 priv->system_clipboard_change_handler_id = 0;
513         }
514         
515         /* This had to stay alive for as long as the combobox that used it: */
516         modest_pair_list_free (priv->from_field_protos);
517         
518         G_OBJECT_CLASS(parent_class)->finalize (obj);
519 }
520
521 static gboolean
522 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMsgEditWindow *self)
523 {
524         GtkWidget *close_dialog;
525         ModestMsgEditWindowPrivate *priv;
526         gint response;
527
528         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
529         modest_window_save_state (MODEST_WINDOW (self));
530         if (is_modified (self)) {
531                 close_dialog = hildon_note_new_confirmation (GTK_WINDOW (self), _("mcen_nc_no_email_message_modified_save_changes"));
532                 response = gtk_dialog_run (GTK_DIALOG (close_dialog));
533                 gtk_widget_destroy (close_dialog);
534
535                 if (response != GTK_RESPONSE_CANCEL) {
536                         modest_ui_actions_on_save_to_drafts (NULL, self);
537                 }
538         } 
539 /*      /\* remove old message from drafts *\/ */
540 /*      if (priv->draft_msg) { */
541 /*              TnyHeader *header = tny_msg_get_header (priv->draft_msg); */
542 /*              TnyAccount *account = modest_tny_account_store_get_server_account (modest_runtime_get_account_store(), */
543 /*                                                                                         account_name, */
544 /*                                                                                         TNY_ACCOUNT_TYPE_STORE); */
545 /*              TnyFolder *folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS); */
546 /*              g_return_val_if_fail (TNY_IS_HEADER (header), FALSE); */
547 /*              g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE); */
548 /*              tny_folder_remove_msg (folder, header, NULL); */
549 /*              g_object_unref (folder); */
550 /*              g_object_unref (header); */
551 /*              g_object_unref (priv->draft_msg); */
552 /*              priv->draft_msg = NULL; */
553 /*      } */
554         gtk_widget_destroy (GTK_WIDGET (self));
555         
556         return TRUE;
557 }
558
559 static GtkWidget *
560 menubar_to_menu (GtkUIManager *ui_manager)
561 {
562         GtkWidget *main_menu;
563         GtkWidget *menubar;
564         GList *iter;
565
566         /* Create new main menu */
567         main_menu = gtk_menu_new();
568
569         /* Get the menubar from the UI manager */
570         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
571
572         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
573         while (iter) {
574                 GtkWidget *menu;
575
576                 menu = GTK_WIDGET (iter->data);
577                 gtk_widget_reparent(menu, main_menu);
578
579                 iter = g_list_next (iter);
580         }
581         return main_menu;
582 }
583
584
585 static void
586 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
587 {
588         TnyHeader *header;
589         const gchar *to, *cc, *bcc, *subject;
590         gchar *body;
591         ModestMsgEditWindowPrivate *priv;
592         GtkTextIter iter;
593         TnyHeaderFlags priority_flags;
594         
595         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
596         g_return_if_fail (TNY_IS_MSG (msg));
597
598         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
599
600         header = tny_msg_get_header (msg);
601         to      = tny_header_get_to (header);
602         cc      = tny_header_get_cc (header);
603         bcc     = tny_header_get_bcc (header);
604         subject = tny_header_get_subject (header);
605         priority_flags = tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY;
606
607         if (to)
608                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
609         if (cc)
610                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
611         if (bcc)
612                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
613         if (subject)
614                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
615         modest_msg_edit_window_set_priority_flags (MODEST_MSG_EDIT_WINDOW(self),
616                                                    priority_flags);
617
618         update_window_title (self);
619
620 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
621         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
622         body = modest_tny_msg_get_body (msg, TRUE);
623
624         if ((body == NULL)||(body[0] == '\0')) {
625                 g_free (body);
626                 body = modest_text_utils_convert_to_html ("");
627         }
628         wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
629         wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
630                                             (gchar *) body,
631                                             strlen (body));
632         wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
633         g_free (body);
634
635         /* Get the default format required from configuration */
636         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL)) {
637                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
638         }
639
640         /* Set the default focus depending on having already a To: field or not */
641         if ((!to)||(*to == '\0')) {
642                 modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
643         } else {
644                 gtk_widget_grab_focus (priv->msg_body);
645         }
646
647         /* TODO: lower priority, select in the From: combo to the
648            value that comes from msg <- not sure, should it be
649            allowed? */
650         
651         /* Add attachments to the view */
652         modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), msg);
653         priv->attachments = modest_attachments_view_get_attachments (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
654         if (priv->attachments == NULL) {
655                 gtk_widget_hide (priv->attachments_caption);
656         } else {
657                 gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
658                 gtk_widget_show_all (priv->attachments_caption);
659         }
660
661         gtk_text_buffer_get_start_iter (priv->text_buffer, &iter);
662         gtk_text_buffer_place_cursor (priv->text_buffer, &iter);
663
664         reset_modified (self);
665
666         update_dimmed (self);
667         text_buffer_can_undo (priv->text_buffer, FALSE, self);
668
669         priv->draft_msg = msg;
670 }
671
672 static void
673 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
674                                 gpointer data)
675 {
676         GList *item_children, *node;
677         GtkWidget *bin_child;
678
679         bin_child = gtk_bin_get_child (GTK_BIN(item));
680
681         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
682         
683         for (node = item_children; node != NULL; node = g_list_next (node)) {
684                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
685                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
686                 }
687         }
688         g_list_free (item_children);
689 }
690
691 static void
692 menu_tool_button_dont_expand (GtkMenuToolButton *item)
693 {
694         GtkWidget *box;
695         GList *item_children, *node;
696
697         box = gtk_bin_get_child (GTK_BIN (item));
698         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
699         item_children = gtk_container_get_children (GTK_CONTAINER (box));
700         
701         for (node = item_children; node != NULL; node = g_list_next (node)) {
702                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
703                 if (GTK_IS_TOGGLE_BUTTON (node->data))
704                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
705                 else if (GTK_IS_BUTTON (node->data))
706                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
707         }
708         g_list_free (item_children);
709 }
710
711
712 static void
713 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
714 {
715         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
716         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
717         GtkWidget *placeholder;
718         GtkWidget *tool_item;
719         gint insert_index;
720         gchar size_text[5];
721         gint size_index;
722         gint font_index;
723         GtkWidget *sizes_menu;
724         GtkWidget *fonts_menu;
725         GSList *radio_group = NULL;
726         GSList *node = NULL;
727         gchar *markup;
728
729         /* Toolbar */
730         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
731         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
732
733         /* should we hide the toolbar? */
734         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
735                 gtk_widget_hide (parent_priv->toolbar);
736
737         /* Font color placeholder */
738         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
739         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
740
741         /* font color */
742         tool_item = GTK_WIDGET (gtk_tool_item_new ());
743         priv->font_color_button = hildon_color_button_new ();
744         GTK_WIDGET_UNSET_FLAGS (tool_item, GTK_CAN_FOCUS);
745         GTK_WIDGET_UNSET_FLAGS (priv->font_color_button, GTK_CAN_FOCUS);
746         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
747         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
748         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
749         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
750         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
751
752         /* Font size and face placeholder */
753         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
754         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
755         /* font_size */
756         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
757         priv->size_tool_button_label = gtk_label_new (NULL);
758         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
759         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
760                               size_text,"</span>", NULL);
761         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
762         g_free (markup);
763         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
764         sizes_menu = gtk_menu_new ();
765         priv->size_items_group = NULL;
766         radio_group = NULL;
767         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
768                 GtkWidget *size_menu_item;
769
770                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
771                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
772                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
773                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
774                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
775                 gtk_widget_show (size_menu_item);
776
777                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
778                         
779         }
780
781         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
782                 GtkWidget *item = (GtkWidget *) node->data;
783                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
784                                   window);
785         }
786
787         priv->size_items_group = g_slist_reverse (priv->size_items_group);
788         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
789         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
790         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
791         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
792         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
793         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
794         priv->font_size_toolitem = tool_item;
795
796         /* font face */
797         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
798         priv->font_tool_button_label = gtk_label_new (NULL);
799         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
800         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
801         g_free(markup);
802         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
803         fonts_menu = gtk_menu_new ();
804         priv->font_items_group = NULL;
805         radio_group = NULL;
806         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
807                 GtkWidget *font_menu_item;
808                 GtkWidget *child_label;
809
810                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
811                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
812                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
813                                       wp_get_font_name (font_index), "</span>", NULL);
814                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
815                 g_free (markup);
816                 
817                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
818                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
819                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
820                 gtk_widget_show (font_menu_item);
821
822                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
823                         
824         }
825         for (node = radio_group; node != NULL; node = g_slist_next (node)) {
826                 GtkWidget *item = (GtkWidget *) node->data;
827                 g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
828                                   window);
829         }
830         priv->font_items_group = g_slist_reverse (priv->font_items_group);
831         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
832         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
833         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
834         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
835         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
836         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
837         priv->font_face_toolitem = tool_item;
838
839         /* Set expand and homogeneous for remaining items */
840         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
841         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
842         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
843         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
844         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
845         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
846         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
847         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
848         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
849
850
851 }
852
853
854
855 ModestWindow*
856 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
857 {
858         GObject *obj;
859         ModestWindowPrivate *parent_priv;
860         ModestMsgEditWindowPrivate *priv;
861         GtkActionGroup *action_group;
862         GError *error = NULL;
863         GdkPixbuf *window_icon = NULL;
864         GtkAction *action;
865         ModestConf *conf;
866         gboolean prefer_formatted;
867         gint file_format;
868         ModestPair *account_pair = NULL;
869
870         g_return_val_if_fail (msg, NULL);
871         g_return_val_if_fail (account_name, NULL);
872         
873         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
874
875         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
876         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
877
878         parent_priv->ui_manager = gtk_ui_manager_new();
879         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
880         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
881
882         /* Add common actions */
883         gtk_action_group_add_actions (action_group,
884                                       modest_msg_edit_action_entries,
885                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
886                                       obj);
887         gtk_action_group_add_toggle_actions (action_group,
888                                              modest_msg_edit_toggle_action_entries,
889                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
890                                              obj);
891         gtk_action_group_add_radio_actions (action_group,
892                                             modest_msg_edit_alignment_radio_action_entries,
893                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
894                                             GTK_JUSTIFY_LEFT,
895                                             G_CALLBACK (modest_ui_actions_on_change_justify),
896                                             obj);
897         gtk_action_group_add_radio_actions (action_group,
898                                             modest_msg_edit_zoom_action_entries,
899                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
900                                             100,
901                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
902                                             obj);
903         gtk_action_group_add_radio_actions (action_group,
904                                             modest_msg_edit_priority_action_entries,
905                                             G_N_ELEMENTS (modest_msg_edit_priority_action_entries),
906                                             0,
907                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_priority),
908                                             obj);
909         gtk_action_group_add_radio_actions (action_group,
910                                             modest_msg_edit_file_format_action_entries,
911                                             G_N_ELEMENTS (modest_msg_edit_file_format_action_entries),
912                                             modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_PREFER_FORMATTED_TEXT, NULL),
913                                             G_CALLBACK (modest_ui_actions_msg_edit_on_change_file_format),
914                                             obj);
915         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
916         g_object_unref (action_group);
917
918         /* Load the UI definition */
919         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml",
920                                          &error);
921         if (error != NULL) {
922                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
923                 g_clear_error (&error);
924         }
925
926         /* Add accelerators */
927         gtk_window_add_accel_group (GTK_WINDOW (obj), 
928                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
929
930         /* Menubar */
931         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
932         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
933
934         /* Init window */
935         init_window (MODEST_MSG_EDIT_WINDOW(obj));
936
937         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
938                 
939         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
940
941         g_signal_connect (G_OBJECT(obj), "delete-event",
942                           G_CALLBACK(on_delete_event), obj);
943
944         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
945
946         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
947
948         setup_insensitive_handlers (MODEST_MSG_EDIT_WINDOW (obj));
949
950         account_pair = modest_pair_list_find_by_first_as_string (priv->from_field_protos, account_name);
951         if (account_pair != NULL)
952                 modest_combo_box_set_active_id (MODEST_COMBO_BOX (priv->from_field), account_pair->first);
953
954         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
955
956         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
957
958         /* Set window icon */
959         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
960         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
961
962         /* Dim at start clipboard actions */
963         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
964         gtk_action_set_sensitive (action, FALSE);
965         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
966         gtk_action_set_sensitive (action, FALSE);
967         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
968         gtk_action_set_sensitive (action, FALSE);
969
970         /* Update select all */
971         update_select_all_dimming (MODEST_MSG_EDIT_WINDOW (obj));
972         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu");
973         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (edit_menu_activated), obj);
974         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu");
975         g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (view_menu_activated), obj);
976
977         /* set initial state of cc and bcc */
978         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewCcFieldMenu");
979         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
980                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL));
981         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewBccFieldMenu");
982         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
983                                       modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL));
984
985         /* Setup the file format */
986         conf = modest_runtime_get_conf ();
987         prefer_formatted = modest_conf_get_bool (conf, MODEST_CONF_PREFER_FORMATTED_TEXT, &error);
988         if (error) {
989                 g_clear_error (&error);
990                 file_format = MODEST_FILE_FORMAT_FORMATTED_TEXT;
991         } else
992                 file_format = (prefer_formatted) ? 
993                         MODEST_FILE_FORMAT_FORMATTED_TEXT : 
994                         MODEST_FILE_FORMAT_PLAIN_TEXT;
995         modest_msg_edit_window_set_file_format (MODEST_MSG_EDIT_WINDOW (obj), file_format);
996
997         update_paste_dimming (MODEST_MSG_EDIT_WINDOW (obj));
998         
999         return (ModestWindow*) obj;
1000 }
1001
1002 static gint
1003 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
1004 {
1005         GString **string_buffer = (GString **) user_data;
1006
1007         *string_buffer = g_string_append (*string_buffer, buffer);
1008    
1009         return 0;
1010 }
1011
1012 /**
1013  * @result: A new string which should be freed with g_free().
1014  */
1015 static gchar *
1016 get_formatted_data (ModestMsgEditWindow *edit_window)
1017 {
1018         ModestMsgEditWindowPrivate *priv;
1019         GString *string_buffer = g_string_new ("");
1020         
1021         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1022
1023         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
1024
1025         return g_string_free (string_buffer, FALSE);
1026                                                                         
1027 }
1028
1029 MsgData * 
1030 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
1031 {
1032         MsgData *data;
1033         const gchar *account_name;
1034         ModestMsgEditWindowPrivate *priv;
1035         
1036         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
1037
1038         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
1039                                                                         
1040         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
1041         g_return_val_if_fail (account_name, NULL);
1042         
1043         
1044         /* don't free these (except from) */
1045         data = g_slice_new0 (MsgData);
1046         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
1047                                                              account_name);
1048         data->account_name = g_strdup (account_name);
1049         data->to      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->to_field)));
1050         data->cc      =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->cc_field)));
1051         data->bcc     =  g_strdup (modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR (priv->bcc_field)));
1052         data->subject =  g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->subject_field)));
1053         if (priv->draft_msg) {
1054                 data->draft_msg = g_object_ref (priv->draft_msg);
1055         } else {
1056                 data->draft_msg = NULL;
1057         }
1058
1059         GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
1060         GtkTextIter b, e;
1061         gtk_text_buffer_get_bounds (buf, &b, &e);
1062         data->plain_body = g_strdup (gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE)); /* returns a copy */
1063
1064         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)))
1065                 data->html_body = get_formatted_data (edit_window); /* returns a copy. */
1066         else
1067                 data->html_body = NULL;
1068
1069         data->attachments = priv->attachments; /* TODO: copy and free ? */
1070         data->priority_flags = priv->priority_flags;
1071
1072         return data;
1073 }
1074
1075 /* TODO: We must duplicate this implementation for GNOME and Maemo, but that is unwise. */
1076 void 
1077 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
1078                                                       MsgData *data)
1079 {
1080         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
1081
1082         if (!data)
1083                 return;
1084
1085         g_free (data->to);
1086         g_free (data->cc);
1087         g_free (data->bcc);
1088         g_free (data->subject);
1089         g_free (data->plain_body);
1090         g_free (data->html_body);
1091         if (data->draft_msg != NULL) {
1092                 g_object_unref (data->draft_msg);
1093                 data->draft_msg = NULL;
1094         }
1095         g_free (data->account_name);
1096
1097         /* TODO: Free data->attachments? */
1098
1099         g_slice_free (MsgData, data);
1100 }
1101
1102 ModestMsgEditFormat
1103 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
1104 {
1105         gboolean rich_text;
1106         ModestMsgEditWindowPrivate *priv = NULL;
1107         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
1108
1109         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1110
1111         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
1112         if (rich_text)
1113                 return MODEST_MSG_EDIT_FORMAT_HTML;
1114         else
1115                 return MODEST_MSG_EDIT_FORMAT_TEXT;
1116 }
1117
1118 void
1119 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
1120                                    ModestMsgEditFormat format)
1121 {
1122         ModestMsgEditWindowPrivate *priv;
1123
1124         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1125         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1126
1127         switch (format) {
1128         case MODEST_MSG_EDIT_FORMAT_HTML:
1129                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
1130                 break;
1131         case MODEST_MSG_EDIT_FORMAT_TEXT:
1132                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
1133                 break;
1134         default:
1135                 g_return_if_reached ();
1136         }
1137 }
1138
1139 ModestMsgEditFormatState *
1140 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
1141 {
1142         ModestMsgEditFormatState *format_state = NULL;
1143         ModestMsgEditWindowPrivate *priv;
1144         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1145
1146         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
1147         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1148
1149         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
1150
1151         format_state = g_new0 (ModestMsgEditFormatState, 1);
1152         format_state->bold = buffer_format->bold&0x1;
1153         format_state->italics = buffer_format->italic&0x1;
1154         format_state->bullet = buffer_format->bullet&0x1;
1155         format_state->color = buffer_format->color;
1156         format_state->font_size = buffer_format->font_size;
1157         format_state->font_family = wp_get_font_name (buffer_format->font);
1158         format_state->justification = buffer_format->justification;
1159         g_free (buffer_format);
1160
1161         return format_state;
1162  
1163 }
1164
1165 void
1166 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
1167                                          const ModestMsgEditFormatState *format_state)
1168 {
1169         ModestMsgEditWindowPrivate *priv;
1170         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1171         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
1172         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
1173         g_return_if_fail (format_state != NULL);
1174
1175         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
1176         gtk_widget_grab_focus (priv->msg_body);
1177         buffer_format->bold = (format_state->bold != FALSE);
1178         buffer_format->italic = (format_state->italics != FALSE);
1179         buffer_format->color = format_state->color;
1180         buffer_format->font_size = format_state->font_size;
1181         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
1182         buffer_format->justification = format_state->justification;
1183         buffer_format->bullet = format_state->bullet;
1184
1185         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
1186
1187         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
1188         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
1189         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
1190         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
1191         buffer_format->cs.font = (buffer_format->font != current_format->font);
1192         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
1193         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
1194
1195         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
1196         if (buffer_format->cs.bold) {
1197                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
1198         }
1199         if (buffer_format->cs.italic) {
1200                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
1201         }
1202         if (buffer_format->cs.color) {
1203                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
1204         }
1205         if (buffer_format->cs.font_size) {
1206                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
1207         }
1208         if (buffer_format->cs.justification) {
1209                 switch (buffer_format->justification) {
1210                 case GTK_JUSTIFY_LEFT:
1211                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
1212                         break;
1213                 case GTK_JUSTIFY_CENTER:
1214                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
1215                         break;
1216                 case GTK_JUSTIFY_RIGHT:
1217                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
1218                         break;
1219                 default:
1220                         break;
1221                 }
1222                         
1223         }
1224         if (buffer_format->cs.font) {
1225                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
1226         }
1227         if (buffer_format->cs.bullet) {
1228                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) ((int)buffer_format->bullet));
1229         }
1230 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
1231         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
1232
1233         g_free (current_format);
1234
1235 }
1236
1237 static void
1238 toggle_action_set_active_block_notify (GtkToggleAction *action,
1239                                        gboolean value)
1240 {
1241         GSList *proxies = NULL;
1242
1243         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1244              proxies != NULL; proxies = g_slist_next (proxies)) {
1245                 GtkWidget *widget = (GtkWidget *) proxies->data;
1246                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
1247         }
1248
1249         gtk_toggle_action_set_active (action, value);
1250
1251         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
1252              proxies != NULL; proxies = g_slist_next (proxies)) {
1253                 GtkWidget *widget = (GtkWidget *) proxies->data;
1254                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
1255         }
1256 }
1257
1258 static void
1259 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
1260 {
1261         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1262         GtkAction *action;
1263         ModestWindowPrivate *parent_priv;
1264         ModestMsgEditWindowPrivate *priv;
1265         GtkWidget *new_size_menuitem;
1266         GtkWidget *new_font_menuitem;
1267         
1268         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1269         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1270
1271         if (wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))) {
1272                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatFormattedTextMenu");
1273                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1274                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1275         } else {
1276                 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/FileFormatMenu/FileFormatPlainTextMenu");
1277                 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1278                         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), TRUE);
1279         }
1280
1281         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1282         
1283         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
1284         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
1285
1286         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
1287         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
1288
1289         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
1290         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
1291
1292         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
1293                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
1294                                          window);
1295         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1296         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1297                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1298                                            window);
1299
1300         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1301                                                       buffer_format->font_size))->data);
1302         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1303                 GtkWidget *label;
1304                 gchar *markup;
1305
1306                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1307                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1308                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1309                 g_free (markup);
1310                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1311                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1312                                                  window);
1313                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1314                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1315                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1316                                                    window);
1317         }
1318
1319         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1320                                                       buffer_format->font))->data);
1321         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1322                 GtkWidget *label;
1323                 gchar *markup;
1324
1325                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1326                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1327                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1328                 g_free (markup);
1329                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1330                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1331                                                  window);
1332                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1333                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1334                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1335                                                    window);
1336         }
1337
1338         g_free (buffer_format);
1339
1340 }
1341
1342
1343 void
1344 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1345 {
1346         
1347         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1348         ModestMsgEditWindowPrivate *priv;
1349         GtkWidget *dialog = NULL;
1350         gint response;
1351         const GdkColor *new_color = NULL;
1352         
1353         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1354         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1355         
1356 #ifdef MODEST_HILDON_VERSION_0  
1357         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1358         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), &(buffer_format->color));
1359 #else
1360         dialog = hildon_color_chooser_new ();
1361         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog), &(buffer_format->color));
1362 #endif /*MODEST_HILDON_VERSION_0*/              
1363         g_free (buffer_format);
1364
1365         response = gtk_dialog_run (GTK_DIALOG (dialog));
1366         switch (response) {
1367         case GTK_RESPONSE_OK: {
1368 #ifdef MODEST_HILDON_VERSION_0
1369                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1370 #else
1371                 GdkColor col;
1372                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1373                 new_color = &col;
1374 #endif /*MODEST_HILDON_VERSION_0*/
1375         }
1376
1377         break;
1378         default:
1379                 break;
1380         }
1381         gtk_widget_destroy (dialog);
1382
1383         if (new_color != NULL)
1384                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1385
1386 }
1387
1388 void
1389 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1390 {
1391         
1392         ModestMsgEditWindowPrivate *priv;
1393         GtkWidget *dialog = NULL;
1394         gint response;
1395         GdkColor *old_color = NULL;
1396         const GdkColor *new_color = NULL;
1397         
1398         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1399         old_color = (GdkColor*)wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1400         
1401 #ifdef MODEST_HILDON_VERSION_0  
1402         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1403         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog),(GdkColor*)old_color);
1404 #else
1405         dialog = hildon_color_chooser_new ();
1406         hildon_color_chooser_set_color (HILDON_COLOR_CHOOSER (dialog),(GdkColor*)old_color);
1407 #endif /*MODEST_HILDON_VERSION_9*/              
1408
1409         response = gtk_dialog_run (GTK_DIALOG (dialog));
1410         switch (response) {
1411         case GTK_RESPONSE_OK: {
1412 #ifdef MODEST_HILDON_VERSION_0
1413                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1414 #else
1415                 GdkColor col;
1416                 hildon_color_chooser_get_color (HILDON_COLOR_CHOOSER(dialog), &col);
1417                 new_color = &col;
1418 #endif /*MODEST_HILDON_VERSION_0*/
1419           }
1420                 break;
1421         default:
1422                 break;
1423         }
1424         gtk_widget_destroy (dialog);
1425
1426         if (new_color != NULL)
1427                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1428
1429 }
1430
1431
1432 void
1433 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1434 {
1435         
1436         ModestMsgEditWindowPrivate *priv;
1437         GtkWidget *dialog = NULL;
1438         gint response = 0;
1439         GSList *uris = NULL;
1440         GSList *uri_node = NULL;
1441         
1442         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1443         
1444         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1445         gtk_window_set_title (GTK_WINDOW (dialog), _("mcen_ia_select_inline_image_title"));
1446         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1447
1448         modest_maemo_utils_setup_images_filechooser (GTK_FILE_CHOOSER (dialog));
1449
1450         response = gtk_dialog_run (GTK_DIALOG (dialog));
1451         switch (response) {
1452         case GTK_RESPONSE_OK:
1453                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1454                 break;
1455         default:
1456                 break;
1457         }
1458         gtk_widget_destroy (dialog);
1459
1460         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1461                 const gchar *uri;
1462                 GnomeVFSHandle *handle = NULL;
1463                 GnomeVFSResult result;
1464                 GtkTextIter position;
1465                 GtkTextMark *insert_mark;
1466
1467                 uri = (const gchar *) uri_node->data;
1468                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1469                 if (result == GNOME_VFS_OK) {
1470                         GdkPixbufLoader *loader;
1471                         GdkPixbuf *pixbuf;
1472                         GnomeVFSFileInfo info;
1473                         gchar *filename, *basename;
1474                         TnyMimePart *mime_part;
1475                         TnyStream *stream;
1476                         gchar *content_id;
1477                         const gchar *mime_type = NULL;
1478
1479                         filename = g_filename_from_uri (uri, NULL, NULL);
1480                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) 
1481                             == GNOME_VFS_OK)
1482                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1483
1484                         mime_part = tny_platform_factory_new_mime_part
1485                                 (modest_runtime_get_platform_factory ());
1486                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1487                         
1488                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1489                         
1490                         content_id = g_strdup_printf ("%d", priv->last_cid);
1491                         tny_mime_part_set_content_id (mime_part, content_id);
1492                         g_free (content_id);
1493                         priv->last_cid++;
1494                         
1495                         basename = g_path_get_basename (filename);
1496                         tny_mime_part_set_filename (mime_part, basename);
1497                         g_free (basename);
1498                         
1499                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1500                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1501                                                                 mime_part);
1502                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1503                         gtk_widget_show_all (priv->attachments_caption);
1504                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1505                         g_free (filename);
1506
1507                         loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, NULL);
1508                         while (!tny_stream_is_eos (TNY_STREAM (stream))) {
1509                                 char read_buffer[128];
1510                                 gint readed;
1511                                 readed = tny_stream_read (TNY_STREAM (stream), read_buffer, 128);
1512                                 if (!gdk_pixbuf_loader_write (loader, read_buffer, readed, NULL))
1513                                         break;
1514                         }
1515                         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1516                         g_object_ref (pixbuf);
1517                         gdk_pixbuf_loader_close (loader, NULL);
1518                         g_object_unref (loader);
1519
1520                         if (gdk_pixbuf_get_width (pixbuf) > IMAGE_MAX_WIDTH) {
1521                                 GdkPixbuf *new_pixbuf;
1522                                 gint new_height;
1523                                 new_height = (gdk_pixbuf_get_height (pixbuf) * IMAGE_MAX_WIDTH) /
1524                                         gdk_pixbuf_get_width (pixbuf);
1525                                 new_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_MAX_WIDTH, new_height, GDK_INTERP_BILINEAR);
1526                                 g_object_unref (pixbuf);
1527                                 pixbuf = new_pixbuf;
1528                         }
1529
1530                         if (pixbuf != NULL) {
1531                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1532                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1533                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (mime_part)), pixbuf);
1534                         } 
1535                 }
1536         }
1537
1538
1539 }
1540
1541 void
1542 modest_msg_edit_window_attach_file (ModestMsgEditWindow *window)
1543 {
1544         
1545         ModestMsgEditWindowPrivate *priv;
1546         GtkWidget *dialog = NULL;
1547         gint response = 0;
1548         GSList *uris = NULL;
1549         GSList *uri_node;
1550         
1551         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1552         
1553         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1554         gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
1555
1556         response = gtk_dialog_run (GTK_DIALOG (dialog));
1557         switch (response) {
1558         case GTK_RESPONSE_OK:
1559                 uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
1560                 break;
1561         default:
1562                 break;
1563         }
1564         gtk_widget_destroy (dialog);
1565
1566         for (uri_node = uris; uri_node != NULL; uri_node = g_slist_next (uri_node)) {
1567                 const gchar *uri;
1568                 GnomeVFSHandle *handle = NULL;
1569                 GnomeVFSResult result;
1570
1571                 uri = (const gchar *) uri_node->data;
1572                 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
1573                 if (result == GNOME_VFS_OK) {
1574                         TnyMimePart *mime_part;
1575                         TnyStream *stream;
1576                         const gchar *mime_type = NULL;
1577                         gchar *basename;
1578                         gchar *filename;
1579                         gchar *content_id;
1580                         GnomeVFSFileInfo info;
1581
1582                         filename = g_filename_from_uri (uri, NULL, NULL);
1583                         
1584                         if (gnome_vfs_get_file_info_from_handle (handle, &info, GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
1585                                 mime_type = gnome_vfs_file_info_get_mime_type (&info);
1586                         mime_part = tny_platform_factory_new_mime_part
1587                                 (modest_runtime_get_platform_factory ());
1588                         stream = TNY_STREAM (tny_vfs_stream_new (handle));
1589                         
1590                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1591                         
1592                         content_id = g_strdup_printf ("%d", priv->last_cid);
1593                         tny_mime_part_set_content_id (mime_part, content_id);
1594                         g_free (content_id);
1595                         priv->last_cid++;
1596                         
1597                         basename = g_path_get_basename (filename);
1598                         tny_mime_part_set_filename (mime_part, basename);
1599                         g_free (basename);
1600                         
1601                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1602                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1603                                                                 mime_part);
1604                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1605                         gtk_widget_show_all (priv->attachments_caption);
1606                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1607                         g_free (filename);
1608
1609                 } 
1610         }
1611         g_slist_foreach (uris, (GFunc) g_free, NULL);
1612         g_slist_free (uris);
1613 }
1614
1615 void
1616 modest_msg_edit_window_attach_file_noninteractive (
1617                 ModestMsgEditWindow *window,
1618                 const gchar *file_uri)
1619 {
1620         
1621         ModestMsgEditWindowPrivate *priv;
1622         
1623         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1624
1625         if (file_uri) {
1626                 gint file_id = 0;
1627                 
1628                 /* TODO: We should probably try to use only the URI,
1629                  * instead of using a filename.
1630                  */
1631                 gchar* filename = g_filename_from_uri (file_uri, NULL, NULL);
1632                 if (!filename) {
1633                         g_warning("%s: g_filename_from_uri(%s) failed.\n", __FUNCTION__, file_uri);
1634                 }
1635
1636                 file_id = g_open (filename, O_RDONLY, 0);
1637                 if (file_id != -1) {
1638                         TnyMimePart *mime_part;
1639                         TnyStream *stream;
1640                         const gchar *mime_type;
1641                         gchar *basename;
1642                         gchar *content_id;
1643                         
1644                         mime_type = gnome_vfs_get_file_mime_type_fast (filename, NULL);
1645                         mime_part = tny_platform_factory_new_mime_part
1646                                 (modest_runtime_get_platform_factory ());
1647                         stream = TNY_STREAM (tny_fs_stream_new (file_id));
1648                         
1649                         tny_mime_part_construct_from_stream (mime_part, stream, mime_type);
1650                         
1651                         content_id = g_strdup_printf ("%d", priv->last_cid);
1652                         tny_mime_part_set_content_id (mime_part, content_id);
1653                         g_free (content_id);
1654                         priv->last_cid++;
1655                         
1656                         basename = g_path_get_basename (filename);
1657                         tny_mime_part_set_filename (mime_part, basename);
1658                         g_free (basename);
1659                         
1660                         priv->attachments = g_list_prepend (priv->attachments, mime_part);
1661                         modest_attachments_view_add_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1662                                                                 mime_part);
1663                         gtk_widget_set_no_show_all (priv->attachments_caption, FALSE);
1664                         gtk_widget_show_all (priv->attachments_caption);
1665                 } else if (file_id == -1) {
1666                         close (file_id);
1667                         g_warning("file to be attached does not exist: %s", filename);
1668                 }
1669
1670                 g_free (filename);
1671         }
1672 }
1673
1674 void
1675 modest_msg_edit_window_remove_attachments (ModestMsgEditWindow *window,
1676                                           GList *att_list)
1677 {
1678         ModestMsgEditWindowPrivate *priv;
1679         gboolean clean_list = FALSE;
1680
1681         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1682         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1683
1684         if (att_list == NULL) {
1685                 att_list = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
1686                 clean_list = TRUE;
1687         }
1688
1689         if (att_list == NULL) {
1690                 hildon_banner_show_information (NULL, NULL, _("TODO: no attachments selected to remove"));
1691         } else {
1692                 GtkWidget *confirmation_dialog = NULL;
1693                 gboolean dialog_response;
1694                 GList *node;
1695                 gchar *message = NULL;
1696                 const gchar *filename = NULL;
1697
1698                 if (att_list->next == NULL) {
1699                         filename = tny_mime_part_get_filename (TNY_MIME_PART (att_list->data));
1700                 } else {
1701                         filename = "";
1702                 }
1703                 message = g_strdup_printf (ngettext("emev_nc_delete_attachment", "emev_nc_delete_attachments",
1704                                                     att_list->next == NULL), filename);
1705                 confirmation_dialog = hildon_note_new_confirmation (GTK_WINDOW (window), message);
1706                 g_free (message);
1707                 dialog_response = (gtk_dialog_run (GTK_DIALOG (confirmation_dialog))==GTK_RESPONSE_OK);
1708                 gtk_widget_destroy (confirmation_dialog);
1709                 if (!dialog_response) {
1710                         if (clean_list)
1711                                 g_list_free (att_list);
1712                         return;
1713                 }
1714                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_removing_attachment"));
1715
1716                 for (node = att_list; node != NULL; node = g_list_next (node)) {
1717                         TnyMimePart *mime_part = (TnyMimePart *) node->data;
1718                         const gchar *att_id;
1719                         priv->attachments = g_list_remove (priv->attachments, mime_part);
1720
1721                         modest_attachments_view_remove_attachment (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
1722                                                                    mime_part);
1723                         if (priv->attachments == NULL)
1724                                 gtk_widget_hide (priv->attachments_caption);
1725                         att_id = tny_mime_part_get_content_id (mime_part);
1726                         if (att_id != NULL)
1727                                 text_buffer_delete_images_by_id (gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)),
1728                                                                  att_id);
1729                         g_object_unref (mime_part);
1730                         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
1731                 }
1732         }
1733
1734         if (clean_list)
1735                 g_list_free (att_list);
1736 }
1737
1738 static void
1739 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1740                                             gpointer userdata)
1741 {
1742         ModestMsgEditWindowPrivate *priv;
1743         GdkColor *new_color;
1744         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1745         
1746 #ifdef MODEST_HILDON_VERSION_0  
1747         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1748 #else 
1749         GdkColor col;
1750         hildon_color_button_get_color (HILDON_COLOR_BUTTON(priv->font_color_button), &col);
1751         new_color = &col;
1752 #endif /*MODEST_HILDON_VERSION_0*/
1753
1754         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1755         
1756         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1757
1758 }
1759
1760 static void
1761 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1762                                     gpointer userdata)
1763 {
1764         ModestMsgEditWindowPrivate *priv;
1765         gint new_size_index;
1766         ModestMsgEditWindow *window;
1767         GtkWidget *label;
1768         
1769         window = MODEST_MSG_EDIT_WINDOW (userdata);
1770         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1771         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1772
1773         if (gtk_check_menu_item_get_active (menu_item)) {
1774                 gchar *markup;
1775                 WPTextBufferFormat format;
1776
1777                 memset (&format, 0, sizeof (format));
1778                 wp_text_buffer_get_current_state (WP_TEXT_BUFFER (priv->text_buffer), &format);
1779
1780                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1781                 
1782                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1783                 format.cs.font_size = TRUE;
1784                 format.cs.text_position = TRUE;
1785                 format.cs.font = TRUE;
1786                 format.font_size = wp_get_font_size_index (new_size_index, DEFAULT_FONT_SIZE);
1787                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &format);
1788
1789 /*              if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, */
1790 /*                                                 (gpointer) wp_get_font_size_index (new_size_index, 12))) */
1791 /*                      wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); */
1792                 
1793                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1794                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1795                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1796                 g_free (markup);
1797         }
1798 }
1799
1800 static void
1801 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1802                                     gpointer userdata)
1803 {
1804         ModestMsgEditWindowPrivate *priv;
1805         gint new_font_index;
1806         ModestMsgEditWindow *window;
1807         GtkWidget *label;
1808         
1809         window = MODEST_MSG_EDIT_WINDOW (userdata);
1810         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1811         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1812
1813         if (gtk_check_menu_item_get_active (menu_item)) {
1814                 gchar *markup;
1815
1816                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1817                 
1818                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1819
1820                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1821                                                    (gpointer) new_font_index))
1822                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1823                 
1824                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1825                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1826                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1827                 g_free (markup);
1828         }
1829 }
1830
1831 static void
1832 modest_msg_edit_window_set_zoom (ModestWindow *window,
1833                                  gdouble zoom)
1834 {
1835         ModestMsgEditWindowPrivate *priv;
1836         ModestWindowPrivate *parent_priv;
1837         GtkRadioAction *zoom_radio_action;
1838      
1839         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1840
1841         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1842         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1843         priv->zoom_level = zoom;
1844         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1845
1846         /* Zoom level menu options should be updated with the current zoom level */
1847         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1848         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1849                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1850         gtk_radio_action_set_current_value (zoom_radio_action, (gint) (zoom*100.0+0.1));
1851 }
1852
1853 static gdouble
1854 modest_msg_edit_window_get_zoom (ModestWindow *window)
1855 {
1856         ModestMsgEditWindowPrivate *priv;
1857      
1858         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1859
1860         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1861         return priv->zoom_level;
1862 }
1863
1864 static gboolean
1865 zoom_allowed (ModestMsgEditWindow *window)
1866 {
1867         GtkWidget *focus;
1868
1869         focus = gtk_window_get_focus (GTK_WINDOW (window));
1870         return (focus != NULL && WP_IS_TEXT_VIEW (focus));
1871 }
1872
1873 static gboolean
1874 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1875 {
1876         ModestWindowPrivate *parent_priv;
1877         GtkRadioAction *zoom_radio_action;
1878         GSList *group, *node;
1879
1880         /* First we check if the text view is focused. If not, zooming is not allowed */
1881         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
1882                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
1883                 return FALSE;
1884         }
1885
1886         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1887         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1888                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1889
1890         group = gtk_radio_action_get_group (zoom_radio_action);
1891
1892         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1893                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1894                 return FALSE;
1895         }
1896
1897         for (node = group; node != NULL; node = g_slist_next (node)) {
1898                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1899                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1900                         return TRUE;
1901                 }
1902         }
1903         return FALSE;
1904 }
1905
1906 static gboolean
1907 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1908 {
1909         ModestWindowPrivate *parent_priv;
1910         GtkRadioAction *zoom_radio_action;
1911         GSList *group, *node;
1912
1913         /* First we check if the text view is focused. If not, zooming is not allowed */
1914         if (!zoom_allowed (MODEST_MSG_EDIT_WINDOW (window))) {
1915                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
1916                 return FALSE;
1917         }
1918
1919         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1920         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1921                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1922
1923         group = gtk_radio_action_get_group (zoom_radio_action);
1924
1925         for (node = group; node != NULL; node = g_slist_next (node)) {
1926                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1927                         if (node->next != NULL) {
1928                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1929                                 return TRUE;
1930                         } else
1931                                 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1932                         break;
1933                 }
1934         }
1935         return FALSE;
1936 }
1937
1938 static gboolean
1939 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1940 {
1941         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1942                 ModestWindowPrivate *parent_priv;
1943                 ModestWindowMgr *mgr;
1944                 gboolean is_fullscreen;
1945                 GtkAction *fs_toggle_action;
1946                 gboolean active;
1947
1948                 mgr = modest_runtime_get_window_mgr ();
1949                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1950
1951                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1952                 
1953                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1954                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1955                 if (is_fullscreen != active)
1956                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1957         }
1958
1959         return FALSE;
1960
1961 }
1962
1963 void
1964 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1965 {
1966         ModestWindowPrivate *parent_priv;
1967         GtkAction *fs_toggle_action;
1968         gboolean active;
1969
1970         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1971
1972         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1973         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1974         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1975 }
1976
1977 void
1978 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1979                                 gboolean show)
1980 {
1981         ModestMsgEditWindowPrivate *priv = NULL;
1982         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1983
1984         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1985         gtk_widget_set_no_show_all (priv->cc_caption, TRUE);
1986         if (show)
1987                 gtk_widget_show (priv->cc_caption);
1988         else
1989                 gtk_widget_hide (priv->cc_caption);
1990         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, show, NULL);
1991 }
1992
1993 void
1994 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1995                                  gboolean show)
1996 {
1997         ModestMsgEditWindowPrivate *priv = NULL;
1998         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1999
2000         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2001         gtk_widget_set_no_show_all (priv->bcc_caption, TRUE);
2002         if (show)
2003                 gtk_widget_show (priv->bcc_caption);
2004         else
2005                 gtk_widget_hide (priv->bcc_caption);
2006         modest_conf_set_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, show, NULL);
2007 }
2008
2009 static void
2010 modest_msg_edit_window_open_addressbook (ModestMsgEditWindow *window,
2011                                          ModestRecptEditor *editor)
2012 {
2013         ModestMsgEditWindowPrivate *priv;
2014
2015         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2016         g_return_if_fail ((editor == NULL) || (MODEST_IS_RECPT_EDITOR (editor)));
2017         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2018
2019         if (editor == NULL) {
2020                 GtkWidget *view_focus;
2021                 view_focus = gtk_window_get_focus (GTK_WINDOW (window));
2022
2023                 /* This code should be kept in sync with ModestRecptEditor. The
2024                    textview inside the recpt editor is the one that really gets the
2025                    focus. As it's inside a scrolled window, and this one inside the
2026                    hbox recpt editor inherits from, we'll need to go up in the 
2027                    hierarchy to know if the text view is part of the recpt editor
2028                    or if it's a different text entry */
2029
2030                 if (gtk_widget_get_parent (view_focus)) {
2031                         GtkWidget *first_parent;
2032
2033                         first_parent = gtk_widget_get_parent (view_focus);
2034                         if (gtk_widget_get_parent (first_parent) && 
2035                             MODEST_IS_RECPT_EDITOR (gtk_widget_get_parent (first_parent))) {
2036                                 editor = MODEST_RECPT_EDITOR (gtk_widget_get_parent (first_parent));
2037                         }
2038                 }
2039
2040                 if (editor == NULL)
2041                         editor = MODEST_RECPT_EDITOR (priv->to_field);
2042
2043         }
2044
2045         modest_address_book_select_addresses (editor);
2046
2047 }
2048
2049 void
2050 modest_msg_edit_window_select_contacts (ModestMsgEditWindow *window)
2051 {
2052         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2053
2054         modest_msg_edit_window_open_addressbook (window, NULL);
2055 }
2056
2057 static void
2058 modest_msg_edit_window_show_toolbar (ModestWindow *self,
2059                                      gboolean show_toolbar)
2060 {
2061         ModestWindowPrivate *parent_priv;
2062         
2063         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
2064         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2065
2066         /* FIXME: we can not just use the code of
2067            modest_msg_edit_window_setup_toolbar because it has a
2068            mixture of both initialization and creation code. */
2069
2070         if (show_toolbar)
2071                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2072         else
2073                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2074 }
2075
2076 void
2077 modest_msg_edit_window_set_priority_flags (ModestMsgEditWindow *window,
2078                                            TnyHeaderFlags priority_flags)
2079 {
2080         ModestMsgEditWindowPrivate *priv;
2081         ModestWindowPrivate *parent_priv;
2082
2083         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2084
2085         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2086         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2087         priority_flags = priority_flags & (TNY_HEADER_FLAG_PRIORITY);
2088
2089         if (priv->priority_flags != priority_flags) {
2090                 GtkAction *priority_action = NULL;
2091
2092                 priv->priority_flags = priority_flags;
2093
2094                 switch (priority_flags) {
2095                 case TNY_HEADER_FLAG_HIGH_PRIORITY:
2096                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_high", GTK_ICON_SIZE_MENU);
2097                         gtk_widget_show (priv->priority_icon);
2098                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2099                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityHighMenu");
2100                         break;
2101                 case TNY_HEADER_FLAG_LOW_PRIORITY:
2102                         gtk_image_set_from_icon_name (GTK_IMAGE (priv->priority_icon), "qgn_list_messaging_low", GTK_ICON_SIZE_MENU);
2103                         gtk_widget_show (priv->priority_icon);
2104                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2105                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityLowMenu");
2106                         break;
2107                 default:
2108                         gtk_widget_hide (priv->priority_icon);
2109                         priority_action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
2110                                                                      "/MenuBar/ToolsMenu/MessagePriorityMenu/MessagePriorityNormalMenu");
2111                         break;
2112                 }
2113                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priority_action), TRUE);
2114                 gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2115         }
2116 }
2117
2118 void
2119 modest_msg_edit_window_set_file_format (ModestMsgEditWindow *window,
2120                                         gint file_format)
2121 {
2122         ModestMsgEditWindowPrivate *priv;
2123         gint current_format;
2124
2125         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2126
2127         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2128
2129         current_format = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer))
2130                 ? MODEST_FILE_FORMAT_FORMATTED_TEXT : MODEST_FILE_FORMAT_PLAIN_TEXT;
2131
2132         if (current_format != file_format) {
2133                 switch (file_format) {
2134                 case MODEST_FILE_FORMAT_FORMATTED_TEXT:
2135                         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
2136                         break;
2137                 case MODEST_FILE_FORMAT_PLAIN_TEXT:
2138                 {
2139                         GtkWidget *dialog;
2140                         gint response;
2141                         dialog = hildon_note_new_confirmation (NULL, _("emev_nc_formatting_lost"));
2142                         response = gtk_dialog_run (GTK_DIALOG (dialog));
2143                         gtk_widget_destroy (dialog);
2144                         if (response == GTK_RESPONSE_OK)
2145                                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
2146                 }
2147                         break;
2148                 }
2149                 update_dimmed (window);
2150         }
2151 }
2152
2153 void
2154 modest_msg_edit_window_select_font (ModestMsgEditWindow *window)
2155 {
2156         GtkWidget *dialog;
2157         ModestMsgEditWindowPrivate *priv;
2158         WPTextBufferFormat oldfmt, fmt;
2159         gint old_position = 0;
2160         gint response = 0;
2161         gint position = 0;
2162         gint font_size;
2163         GdkColor *color = NULL;
2164         gboolean bold, bold_set, italic, italic_set;
2165         gboolean underline, underline_set;
2166         gboolean strikethrough, strikethrough_set;
2167         gboolean position_set;
2168         gboolean font_size_set, font_set, color_set;
2169         gchar *font_name;
2170
2171         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2172         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2173         
2174         dialog = hildon_font_selection_dialog_new (GTK_WINDOW (window), NULL);
2175
2176         /* First we get the currently selected font information */
2177         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), &oldfmt, TRUE);
2178         g_object_set (G_OBJECT (dialog), "font-scaling", priv->zoom_level, NULL);
2179
2180         switch (oldfmt.text_position) {
2181         case TEXT_POSITION_NORMAL:
2182                 old_position = 0;
2183                 break;
2184         case TEXT_POSITION_SUPERSCRIPT:
2185                 old_position = 1;
2186                 break;
2187         default:
2188                 old_position = -1;
2189                 break;
2190         }
2191
2192         g_object_set (G_OBJECT (dialog),
2193                       "bold", oldfmt.bold != FALSE,
2194                       "bold-set", !oldfmt.cs.bold,
2195                       "underline", oldfmt.underline != FALSE,
2196                       "underline-set", !oldfmt.cs.underline,
2197                       "italic", oldfmt.italic != FALSE,
2198                       "italic-set", !oldfmt.cs.italic,
2199                       "strikethrough", oldfmt.strikethrough != FALSE,
2200                       "strikethrough-set", !oldfmt.cs.strikethrough,
2201                       "color", &oldfmt.color,
2202                       "color-set", !oldfmt.cs.color,
2203                       "size", wp_font_size[oldfmt.font_size],
2204                       "size-set", !oldfmt.cs.font_size,
2205                       "position", old_position,
2206                       "position-set", !oldfmt.cs.text_position,
2207                       "family", wp_get_font_name (oldfmt.font),
2208                       "family-set", !oldfmt.cs.font,
2209                       NULL);
2210
2211         gtk_widget_show_all (dialog);
2212         response = gtk_dialog_run (GTK_DIALOG (dialog));
2213         if (response == GTK_RESPONSE_OK) {
2214
2215                 g_object_get( dialog,
2216                               "bold", &bold,
2217                               "bold-set", &bold_set,
2218                               "underline", &underline,
2219                               "underline-set", &underline_set,
2220                               "italic", &italic,
2221                               "italic-set", &italic_set,
2222                               "strikethrough", &strikethrough,
2223                               "strikethrough-set", &strikethrough_set,
2224                               "color", &color,
2225                               "color-set", &color_set,
2226                               "size", &font_size,
2227                               "size-set", &font_size_set,
2228                               "family", &font_name,
2229                               "family-set", &font_set,
2230                               "position", &position,
2231                               "position-set", &position_set,
2232                               NULL );
2233                 
2234         }       
2235
2236         if (response == GTK_RESPONSE_OK) {
2237                 memset(&fmt, 0, sizeof(fmt));
2238                 if (bold_set) {
2239                         fmt.bold = bold;
2240                         fmt.cs.bold = TRUE;
2241                 }
2242                 if (italic_set) {
2243                         fmt.italic = italic;
2244                         fmt.cs.italic = TRUE;
2245                 }
2246                 if (underline_set) {
2247                         fmt.underline = underline;
2248                         fmt.cs.underline = TRUE;
2249                 }
2250                 if (strikethrough_set) {
2251                         fmt.strikethrough = strikethrough;
2252                         fmt.cs.strikethrough = TRUE;
2253                 }
2254                 if (position_set) {
2255                         fmt.text_position =
2256                                 ( position == 0 )
2257                                 ? TEXT_POSITION_NORMAL
2258                                 : ( ( position == 1 )
2259                                     ? TEXT_POSITION_SUPERSCRIPT
2260                                     : TEXT_POSITION_SUBSCRIPT );
2261                         fmt.cs.text_position = TRUE;
2262                 }
2263                 if (color_set) {
2264                         fmt.color = *color;
2265                         fmt.cs.color = TRUE;
2266                 }
2267                 if (font_set) {
2268                         fmt.font = wp_get_font_index(font_name,
2269                                                      DEFAULT_FONT);
2270                         fmt.cs.font = TRUE;
2271                 }
2272                 g_free(font_name);
2273                 if (font_size_set) {
2274                         fmt.font_size = wp_get_font_size_index(
2275                                 font_size, DEFAULT_FONT_SIZE);
2276                         fmt.cs.font_size = TRUE;
2277                 }
2278                 wp_text_buffer_set_format(WP_TEXT_BUFFER(priv->text_buffer), &fmt);
2279         }
2280         gtk_widget_destroy (dialog);
2281         
2282         gtk_widget_grab_focus(GTK_WIDGET(priv->msg_body));
2283 }
2284
2285 void
2286 modest_msg_edit_window_undo (ModestMsgEditWindow *window)
2287 {
2288         ModestMsgEditWindowPrivate *priv;
2289
2290         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2291         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2292         
2293         wp_text_buffer_undo (WP_TEXT_BUFFER (priv->text_buffer));
2294
2295         update_dimmed (window);
2296
2297 }
2298
2299 static void
2300 update_dimmed (ModestMsgEditWindow *window)
2301 {
2302         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2303         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2304         GtkAction *action;
2305         GtkWidget *widget;
2306         gboolean rich_text;
2307         gboolean editor_focused;
2308
2309         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2310         editor_focused = gtk_widget_is_focus (priv->msg_body);
2311
2312         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2313         gtk_action_set_sensitive (action, rich_text && editor_focused);
2314         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2315         gtk_action_set_sensitive (action, rich_text && editor_focused);
2316         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2317         gtk_action_set_sensitive (action, rich_text && editor_focused);
2318         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2319         gtk_action_set_sensitive (action, rich_text && editor_focused);
2320         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2321         gtk_action_set_sensitive (action, rich_text && editor_focused);
2322         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2323         gtk_action_set_sensitive (action, rich_text && editor_focused);
2324         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2325         gtk_action_set_sensitive (action, rich_text && editor_focused);
2326         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2327         gtk_action_set_sensitive (action, rich_text && editor_focused);
2328         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2329         gtk_action_set_sensitive (action, rich_text && editor_focused);
2330         widget = priv->font_color_button;
2331         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2332         widget = priv->font_size_toolitem;
2333         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2334         widget = priv->font_face_toolitem;
2335         gtk_widget_set_sensitive (widget, rich_text && editor_focused);
2336 }
2337
2338 static void
2339 setup_insensitive_handlers (ModestMsgEditWindow *window)
2340 {
2341         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2342         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2343         GtkWidget *widget;
2344
2345         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2346         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2347         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2348         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (send_insensitive_press), window);
2349
2350         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/SelectFontMenu");
2351         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2352         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
2353         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2354         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu");
2355         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2356         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentLeftMenu");
2357         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2358         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentCenterMenu");
2359         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2360         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/FormatMenu/AlignmentMenu/AlignmentRightMenu");
2361         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2362         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/InsertImageMenu");
2363         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2364         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
2365         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2366         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
2367         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2368         widget = priv->font_color_button;
2369         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2370         widget = priv->font_size_toolitem;
2371         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2372         widget = priv->font_face_toolitem;
2373         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (style_insensitive_press), window);
2374
2375         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2376         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (remove_attachment_insensitive_press), window);
2377         widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
2378         g_signal_connect (G_OBJECT (widget), "insensitive-press", G_CALLBACK (zoom_insensitive_press), window);
2379 }
2380
2381 static void  
2382 text_buffer_can_undo (GtkTextBuffer *buffer, gboolean can_undo, ModestMsgEditWindow *window)
2383 {
2384         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2385         GtkAction *action;
2386
2387         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/UndoMenu");
2388         gtk_action_set_sensitive (action, can_undo);
2389 }
2390
2391 static void
2392 text_buffer_delete_images_by_id (GtkTextBuffer *buffer, const gchar * image_id)
2393 {
2394         GtkTextIter iter;
2395         GtkTextIter match_start, match_end;
2396
2397         if (image_id == NULL)
2398                 return;
2399
2400         gtk_text_buffer_get_start_iter (buffer, &iter);
2401
2402         while (gtk_text_iter_forward_search (&iter, "\xef\xbf\xbc", 0, &match_start, &match_end, NULL)) {
2403                 GSList *tags = gtk_text_iter_get_tags (&match_start);
2404                 GSList *node;
2405                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2406                         GtkTextTag *tag = (GtkTextTag *) node->data;
2407                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2408                                 gchar *cur_image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2409                                 if ((cur_image_id != NULL) && (strcmp (image_id, cur_image_id)==0)) {
2410                                         gint offset;
2411                                         offset = gtk_text_iter_get_offset (&match_start);
2412                                         gtk_text_buffer_delete (buffer, &match_start, &match_end);
2413                                         gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
2414                                 }
2415                         }
2416                 }
2417                 gtk_text_iter_forward_char (&iter);
2418         }
2419 }
2420
2421 static void
2422 text_buffer_delete_range (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, gpointer userdata)
2423 {
2424         ModestMsgEditWindow *window = (ModestMsgEditWindow *) userdata;
2425         GtkTextIter real_start, real_end;
2426         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2427
2428         if (gtk_text_iter_compare (start, end) > 0) {
2429                 real_start = *end;
2430                 real_end = *start;
2431         } else {
2432                 real_start = *start;
2433                 real_end = *end;
2434         }
2435         do {
2436                 GSList *tags = gtk_text_iter_get_tags (&real_start);
2437                 GSList *node;
2438                 for (node = tags; node != NULL; node = g_slist_next (node)) {
2439                         GtkTextTag *tag = (GtkTextTag *) node->data;
2440                         if (g_object_get_data (G_OBJECT (tag), "image-set") != NULL) {
2441                                 gchar *image_id = g_object_get_data (G_OBJECT (tag), "image-index");
2442
2443                                 modest_attachments_view_remove_attachment_by_id (MODEST_ATTACHMENTS_VIEW (priv->attachments_view),
2444                                                                                  image_id);
2445                                 gtk_text_buffer_remove_tag (buffer, tag, start, end);
2446                         }
2447                 }
2448         } while (gtk_text_iter_forward_char (&real_start)&&
2449                  (gtk_text_iter_compare (&real_start, &real_end)<=0));
2450 }
2451
2452 static gboolean
2453 msg_body_focus (GtkWidget *focus,
2454                 GdkEventFocus *event,
2455                 gpointer userdata)
2456 {
2457         
2458         update_dimmed (MODEST_MSG_EDIT_WINDOW (userdata));
2459         return FALSE;
2460 }
2461
2462 static void
2463 recpt_field_changed (GtkTextBuffer *buffer,
2464                   ModestMsgEditWindow *editor)
2465 {
2466         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2467         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2468         GtkTextBuffer *to_buffer, *cc_buffer, *bcc_buffer;
2469         gboolean dim = FALSE;
2470         GtkAction *action;
2471
2472         to_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field));
2473         cc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field));
2474         bcc_buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field));
2475         
2476         dim = ((gtk_text_buffer_get_char_count (to_buffer) + 
2477                 gtk_text_buffer_get_char_count (cc_buffer) +
2478                 gtk_text_buffer_get_char_count (bcc_buffer)) == 0);
2479                         
2480         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSend");
2481         gtk_action_set_sensitive (action, !dim);
2482         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EmailMenu/SendMenu");
2483         gtk_action_set_sensitive (action, !dim);
2484 }
2485
2486 static void  
2487 send_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2488 {
2489         hildon_banner_show_information (NULL, NULL, _("mcen_ib_add_recipients_first"));
2490 }
2491
2492 static void  
2493 zoom_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2494 {
2495         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2496 }
2497
2498 static void  
2499 remove_attachment_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2500 {
2501         ModestWindowPrivate *parent_priv;
2502         ModestMsgEditWindowPrivate *priv;
2503         GList *selected_attachments = NULL;
2504         gint n_att_selected = 0;
2505
2506         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2507         parent_priv = MODEST_WINDOW_GET_PRIVATE (editor);
2508
2509         selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2510         n_att_selected = g_list_length (selected_attachments);
2511         g_list_free (selected_attachments);
2512
2513         if (n_att_selected > 1)
2514                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2515         else if (n_att_selected == 0)
2516                 hildon_banner_show_information (NULL, NULL, _("TODO: select one attachment"));
2517                 
2518 }
2519
2520 static void
2521 style_insensitive_press (GtkWidget *widget, ModestMsgEditWindow *editor)
2522 {
2523         gboolean rich_text, editor_focused;
2524
2525         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2526         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
2527         editor_focused = gtk_widget_is_focus (priv->msg_body);
2528
2529         if (!rich_text)
2530                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_item_unavailable_plaintext"));
2531         else if (!editor_focused)
2532                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_move_cursor_to_message"));
2533 }
2534
2535 static void
2536 reset_modified (ModestMsgEditWindow *editor)
2537 {
2538         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2539         GtkTextBuffer *buffer;
2540
2541         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2542         gtk_text_buffer_set_modified (buffer, FALSE);
2543         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2544         gtk_text_buffer_set_modified (buffer, FALSE);
2545         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2546         gtk_text_buffer_set_modified (buffer, FALSE);
2547         gtk_text_buffer_set_modified (priv->text_buffer, FALSE);
2548 }
2549
2550 static gboolean
2551 is_modified (ModestMsgEditWindow *editor)
2552 {
2553         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (editor);
2554         GtkTextBuffer *buffer;
2555
2556         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->to_field));
2557         if (gtk_text_buffer_get_modified (buffer))
2558                 return TRUE;
2559         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->cc_field));
2560         if (gtk_text_buffer_get_modified (buffer))
2561                 return TRUE;
2562         buffer = modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR(priv->bcc_field));
2563         if (gtk_text_buffer_get_modified (buffer))
2564                 return TRUE;
2565         if (gtk_text_buffer_get_modified (priv->text_buffer))
2566                 return TRUE;
2567
2568         return FALSE;
2569 }
2570
2571 gboolean
2572 modest_msg_edit_window_check_names (ModestMsgEditWindow *window)
2573 {
2574         ModestMsgEditWindowPrivate *priv = NULL;
2575
2576         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), FALSE);
2577         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2578
2579         /* check if there's no recipient added */
2580         if ((gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->to_field))) == 0) &&
2581             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->cc_field))) == 0) &&
2582             (gtk_text_buffer_get_char_count (modest_recpt_editor_get_buffer (MODEST_RECPT_EDITOR (priv->bcc_field))) == 0)) {
2583                 /* no recipient contents, then select contacts */
2584                 modest_msg_edit_window_open_addressbook (window, NULL);
2585                 return FALSE;
2586         }
2587
2588         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->to_field)))
2589                 return FALSE;
2590         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->cc_field)))
2591                 return FALSE;
2592         if (!modest_address_book_check_names (MODEST_RECPT_EDITOR (priv->bcc_field)))
2593                 return FALSE;
2594
2595         modest_recpt_editor_grab_focus (MODEST_RECPT_EDITOR (priv->to_field));
2596
2597         return TRUE;
2598
2599 }
2600
2601 static void
2602 modest_msg_edit_window_add_attachment_clicked (GtkButton *button,
2603                                                ModestMsgEditWindow *window)
2604 {
2605         modest_msg_edit_window_attach_file (window);
2606 }
2607
2608 static void
2609 modest_msg_edit_window_clipboard_owner_change (GtkClipboard *clipboard,
2610                                                GdkEvent *event,
2611                                                ModestMsgEditWindow *window)
2612 {
2613         ModestWindowPrivate *parent_priv;
2614         ModestMsgEditWindowPrivate *priv;
2615         GtkAction *action;
2616         gchar *selection;
2617         GtkWidget *focused;
2618         GList *selected_attachments = NULL;
2619         gint n_att_selected = 0;
2620
2621         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2622         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2623         selection = gtk_clipboard_wait_for_text (clipboard);
2624         focused = gtk_window_get_focus (GTK_WINDOW (window));
2625
2626         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CutMenu");
2627         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2628         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/CopyMenu");
2629         gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused)));
2630
2631         selected_attachments = modest_attachments_view_get_selection (MODEST_ATTACHMENTS_VIEW (priv->attachments_view));
2632         n_att_selected = g_list_length (selected_attachments);
2633         g_list_free (selected_attachments);
2634
2635         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/AttachmentsMenu/RemoveAttachmentsMenu");
2636         gtk_action_set_sensitive (action, n_att_selected == 1);
2637         
2638
2639         update_paste_dimming (window);
2640 }
2641
2642 static void 
2643 update_window_title (ModestMsgEditWindow *window)
2644 {
2645         ModestMsgEditWindowPrivate *priv = NULL;
2646         const gchar *subject;
2647
2648         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2649         subject = gtk_entry_get_text (GTK_ENTRY (priv->subject_field));
2650         if (subject == NULL || subject[0] == '\0')
2651                 subject = _("mail_va_new_email");
2652
2653         gtk_window_set_title (GTK_WINDOW (window), subject);
2654
2655 }
2656
2657 static void  
2658 subject_field_changed (GtkEditable *editable, 
2659                        ModestMsgEditWindow *window)
2660 {
2661         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2662         update_window_title (window);
2663         gtk_text_buffer_set_modified (priv->text_buffer, TRUE);
2664 }
2665
2666 void
2667 modest_msg_edit_window_toggle_find_toolbar (ModestMsgEditWindow *window,
2668                                             gboolean show)
2669 {
2670         ModestMsgEditWindowPrivate *priv = NULL;
2671
2672         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
2673         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2674
2675         gtk_widget_set_no_show_all (priv->find_toolbar, FALSE);
2676         if (show) {
2677                 gtk_widget_show_all (priv->find_toolbar);
2678                 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
2679         } else {
2680                 gtk_widget_hide_all (priv->find_toolbar);
2681                 gtk_widget_grab_focus (priv->msg_body);
2682         }
2683     
2684 }
2685
2686 static void 
2687 modest_msg_edit_window_find_toolbar_search (GtkWidget *widget,
2688                                             ModestMsgEditWindow *window)
2689 {
2690         gchar *current_search = NULL;
2691         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
2692         gboolean result;
2693         GtkTextIter selection_start, selection_end;
2694         GtkTextIter match_start, match_end;
2695
2696         g_object_get (G_OBJECT (widget), "prefix", &current_search, NULL);
2697         if ((current_search == NULL) && (strcmp (current_search, "") == 0)) {
2698                 g_free (current_search);
2699                 return;
2700         }
2701
2702         gtk_text_buffer_get_selection_bounds (priv->text_buffer, &selection_start, &selection_end);
2703         result = gtk_text_iter_forward_search (&selection_end, current_search, GTK_TEXT_SEARCH_VISIBLE_ONLY, &match_start, &match_end, NULL);
2704         if (!result) {
2705                 GtkTextIter buffer_start;
2706                 gtk_text_buffer_get_start_iter (priv->text_buffer, &buffer_start);
2707                 result = gtk_text_iter_forward_search (&buffer_start, current_search, GTK_TEXT_SEARCH_VISIBLE_ONLY, &match_start, &match_end, &selection_start);
2708         }
2709         if (result) {
2710                 gtk_text_buffer_select_range (priv->text_buffer, &match_start, &match_end);
2711                 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (priv->msg_body), &match_start, 0.0, TRUE, 0.0, 0.0);
2712         } else {
2713                 /* TODO: warning about non succesful search */
2714         }
2715         g_free (current_search);
2716 }
2717
2718 static void
2719 modest_msg_edit_window_find_toolbar_close (GtkWidget *widget,
2720                                            ModestMsgEditWindow *window)
2721 {
2722         GtkToggleAction *toggle;
2723         ModestWindowPrivate *parent_priv;
2724         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2725
2726         toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/FindInMessageMenu"));
2727         gtk_toggle_action_set_active (toggle, FALSE);
2728 }
2729
2730
2731 static void 
2732 update_paste_dimming (ModestMsgEditWindow *window)
2733 {
2734         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2735         GtkAction *action = NULL;
2736         GtkClipboard *clipboard = NULL;
2737
2738         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2739
2740         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/PasteMenu");
2741         gtk_action_set_sensitive (action, gtk_clipboard_wait_is_text_available (clipboard));
2742
2743 }
2744
2745 static void
2746 modest_msg_edit_window_system_clipboard_owner_change (GtkClipboard *clipboard,
2747                                                       GdkEvent *event,
2748                                                       ModestMsgEditWindow *window)
2749 {
2750         update_paste_dimming (window);
2751 }
2752
2753 static void 
2754 update_select_all_dimming (ModestMsgEditWindow *window)
2755 {
2756         GtkWidget *focused;
2757         gboolean dimmed = FALSE;
2758         GtkAction *action;
2759         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2760
2761         focused = gtk_window_get_focus (GTK_WINDOW (window));
2762         if (GTK_IS_ENTRY (focused)) {
2763                 const gchar *current_text;
2764                 current_text = gtk_entry_get_text (GTK_ENTRY (focused));
2765                 dimmed = ((current_text == NULL) || (current_text[0] == '\0'));
2766         } else if (GTK_IS_TEXT_VIEW (focused)) {
2767                 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focused));
2768                 dimmed = (gtk_text_buffer_get_char_count (buffer) < 1);
2769         } else if (MODEST_IS_ATTACHMENTS_VIEW (focused)) {
2770                 dimmed = FALSE;
2771         }
2772         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/SelectAllMenu");
2773         gtk_action_set_sensitive (action, !dimmed);
2774 }
2775
2776 static void 
2777 update_zoom_dimming (ModestMsgEditWindow *window)
2778 {
2779         GtkWidget *focused;
2780         gboolean dimmed = FALSE;
2781         GtkAction *action;
2782         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
2783
2784         focused = gtk_window_get_focus (GTK_WINDOW (window));
2785         dimmed = ! WP_IS_TEXT_VIEW (focused);
2786         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ZoomMenu");
2787         gtk_action_set_sensitive (action, !dimmed);
2788 }
2789
2790 static void
2791 edit_menu_activated (GtkAction *action,
2792                      gpointer userdata)
2793 {
2794         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
2795
2796         update_select_all_dimming (window);
2797 }
2798 static void
2799 view_menu_activated (GtkAction *action,
2800                      gpointer userdata)
2801 {
2802         ModestMsgEditWindow *window = MODEST_MSG_EDIT_WINDOW (userdata);
2803
2804         update_zoom_dimming (window);
2805 }