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