* src/maemo/modest-msg-edit-window.c:
[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
38 #include <config.h>
39
40 #include <modest-account-mgr.h>
41 #include <modest-account-mgr-helpers.h>
42
43 #include <widgets/modest-msg-edit-window.h>
44 #include <widgets/modest-combo-box.h>
45 #include <widgets/modest-recpt-editor.h>
46
47 #include <modest-runtime.h>
48
49 #include "modest-platform.h"
50 #include "modest-icon-names.h"
51 #include "modest-widget-memory.h"
52 #include "modest-window-priv.h"
53 #include "modest-mail-operation.h"
54 #include "modest-tny-platform-factory.h"
55 #include "modest-tny-msg.h"
56 #include <tny-simple-list.h>
57 #include <wptextview.h>
58 #include <wptextbuffer.h>
59 #include <hildon-widgets/hildon-color-selector.h>
60 #include <hildon-widgets/hildon-color-button.h>
61 #include <hildon-widgets/hildon-banner.h>
62 #include <hildon-widgets/hildon-caption.h>
63 #include "widgets/modest-msg-edit-window-ui.h"
64
65 #ifdef MODEST_HILDON_VERSION_0
66 #include <hildon-widgets/hildon-file-chooser-dialog.h>
67 #else
68 #include <hildon/hildon-file-chooser-dialog.h>
69
70 #endif /*MODEST_HILDON_VERSION_0 */
71
72
73
74 #define DEFAULT_FONT_SIZE 3
75 #define DEFAULT_FONT 2
76 #define DEFAULT_SIZE_BUTTON_FONT_FAMILY "Sans"
77 #define DEFAULT_SIZE_COMBOBOX_WIDTH 80
78 #define DEFAULT_MAIN_VBOX_SPACING 6
79 #define SUBJECT_MAX_LENGTH 1000
80
81 static void  modest_msg_edit_window_class_init   (ModestMsgEditWindowClass *klass);
82 static void  modest_msg_edit_window_init         (ModestMsgEditWindow *obj);
83 static void  modest_msg_edit_window_finalize     (GObject *obj);
84
85 static void  text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window);
86 static void  text_buffer_mark_set (GtkTextBuffer *buffer, GtkTextIter *location, GtkTextMark *mark, gpointer userdata);
87 static void  modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
88                                                          gpointer userdata);
89 static void  modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
90                                                  gpointer userdata);
91 static void  modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
92                                                  gpointer userdata);
93 static void  modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window);
94 static gboolean modest_msg_edit_window_window_state_event (GtkWidget *widget, 
95                                                            GdkEventWindowState *event, 
96                                                            gpointer userdata);
97
98 /* ModestWindow methods implementation */
99 static void  modest_msg_edit_window_set_zoom (ModestWindow *window, gdouble zoom);
100 static gdouble modest_msg_edit_window_get_zoom (ModestWindow *window);
101 static gboolean modest_msg_edit_window_zoom_minus (ModestWindow *window);
102 static gboolean modest_msg_edit_window_zoom_plus (ModestWindow *window);
103
104
105
106 /* list my signals */
107 enum {
108         /* MY_SIGNAL_1, */
109         /* MY_SIGNAL_2, */
110         LAST_SIGNAL
111 };
112
113 typedef struct _ModestMsgEditWindowPrivate ModestMsgEditWindowPrivate;
114 struct _ModestMsgEditWindowPrivate {
115         GtkWidget   *msg_body;
116         GtkWidget   *header_box;
117         GtkWidget   *from_field;
118         GtkWidget   *to_field;
119         GtkWidget   *cc_field;
120         GtkWidget   *bcc_field;
121         GtkWidget   *subject_field;
122
123         GtkWidget   *cc_caption;
124         GtkWidget   *bcc_caption;
125
126         GtkTextBuffer *text_buffer;
127
128         GtkWidget   *font_color_button;
129         GSList      *font_items_group;
130         GtkWidget   *font_tool_button_label;
131         GSList      *size_items_group;
132         GtkWidget   *size_tool_button_label;
133
134         GtkWidget   *scroll;
135
136         gint last_cid;
137         GList *attachments;
138
139         gdouble zoom_level;
140 };
141
142 #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
143                                                     MODEST_TYPE_MSG_EDIT_WINDOW, \
144                                                     ModestMsgEditWindowPrivate))
145 /* globals */
146 static GtkWindowClass *parent_class = NULL;
147
148 /* uncomment the following if you have defined any signals */
149 /* static guint signals[LAST_SIGNAL] = {0}; */
150
151 GType
152 modest_msg_edit_window_get_type (void)
153 {
154         static GType my_type = 0;
155         if (!my_type) {
156                 static const GTypeInfo my_info = {
157                         sizeof(ModestMsgEditWindowClass),
158                         NULL,           /* base init */
159                         NULL,           /* base finalize */
160                         (GClassInitFunc) modest_msg_edit_window_class_init,
161                         NULL,           /* class finalize */
162                         NULL,           /* class data */
163                         sizeof(ModestMsgEditWindow),
164                         1,              /* n_preallocs */
165                         (GInstanceInitFunc) modest_msg_edit_window_init,
166                         NULL
167                 };
168                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
169                                                   "ModestMsgEditWindow",
170                                                   &my_info, 0);
171
172                 wp_text_buffer_library_init ();
173         }
174         return my_type;
175 }
176
177 static void
178 modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass)
179 {
180         GObjectClass *gobject_class;
181         ModestWindowClass *modest_window_class;
182         gobject_class = (GObjectClass*) klass;
183         modest_window_class = (ModestWindowClass*) klass;
184
185         parent_class            = g_type_class_peek_parent (klass);
186         gobject_class->finalize = modest_msg_edit_window_finalize;
187
188         modest_window_class->set_zoom_func = modest_msg_edit_window_set_zoom;
189         modest_window_class->get_zoom_func = modest_msg_edit_window_get_zoom;
190         modest_window_class->zoom_plus_func = modest_msg_edit_window_zoom_plus;
191         modest_window_class->zoom_minus_func = modest_msg_edit_window_zoom_minus;
192
193         g_type_class_add_private (gobject_class, sizeof(ModestMsgEditWindowPrivate));
194 }
195
196 static void
197 modest_msg_edit_window_init (ModestMsgEditWindow *obj)
198 {
199         ModestMsgEditWindowPrivate *priv;
200         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
201
202         priv->msg_body      = NULL;
203         priv->from_field    = NULL;
204         priv->to_field      = NULL;
205         priv->cc_field      = NULL;
206         priv->bcc_field     = NULL;
207         priv->subject_field = NULL;
208         priv->attachments   = NULL;
209         priv->last_cid      = 0;
210         priv->zoom_level    = 1.0;
211
212         priv->cc_caption    = NULL;
213         priv->bcc_caption    = NULL;
214 }
215
216
217
218 static void
219 save_settings (ModestMsgEditWindow *self)
220 {
221         modest_widget_memory_save (modest_runtime_get_conf(),
222                                    G_OBJECT(self), "modest-edit-msg-window");
223 }
224
225
226 static void
227 restore_settings (ModestMsgEditWindow *self)
228 {
229         modest_widget_memory_restore (modest_runtime_get_conf(),
230                                       G_OBJECT(self), "modest-edit-msg-window");
231 }
232
233
234 /* FIXME: this is a dup from the one in gtk/ */
235 static ModestPairList*
236 get_transports (void)
237 {
238         ModestAccountMgr *account_mgr;
239         GSList *transports = NULL;
240         GSList *cursor, *accounts;
241         
242         account_mgr = modest_runtime_get_account_mgr();
243         cursor = accounts = modest_account_mgr_account_names (account_mgr); 
244         while (cursor) {
245                 gchar *account_name = (gchar*)cursor->data;
246                 gchar *from_string  = modest_account_mgr_get_from_string (account_mgr,
247                                                                           account_name);
248                 if (!from_string)  {
249                         /* something went wrong: ignore this one */
250                         g_free (account_name);
251                         cursor->data = NULL;
252                 } else {
253                         ModestPair *pair;
254                         pair = modest_pair_new ((gpointer) account_name,
255                                                 (gpointer) from_string , TRUE);
256                         transports = g_slist_prepend (transports, pair);
257                 } /* don't free account name; it's freed when the transports list is freed */
258                 cursor = cursor->next;
259         }
260         g_slist_free (accounts);
261         return transports;
262 }
263
264
265 static void
266 text_buffer_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark, gpointer userdata)
267 {
268         ModestMsgEditWindow *window;
269         ModestMsgEditWindowPrivate *priv;
270         GdkRectangle location;
271         gint v_scroll_min_value = 0;
272         gint v_scroll_max_value = 0;
273         gint v_scroll_visible;
274         GtkAdjustment *vadj;
275         GtkTextMark *insert_mark;
276         GtkTextIter insert_iter;
277         
278         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (userdata));
279         g_return_if_fail (GTK_IS_TEXT_MARK (mark));
280         window = MODEST_MSG_EDIT_WINDOW (userdata);
281         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
282                 
283         insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
284         gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &insert_iter, insert_mark);
285         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->msg_body), &insert_iter, &location);
286         
287         if (priv->header_box)
288                 v_scroll_min_value += priv->header_box->allocation.height + DEFAULT_MAIN_VBOX_SPACING;
289         v_scroll_min_value += location.y;
290         v_scroll_max_value = v_scroll_min_value + location.height;
291         
292         v_scroll_visible = GTK_WIDGET (window)->allocation.height;
293         
294         vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll));
295         
296         if (((gdouble) v_scroll_min_value) < vadj->value)
297                 gtk_adjustment_set_value (vadj, v_scroll_min_value);
298         else if (((gdouble) v_scroll_max_value) > (vadj->value + vadj->page_size))
299                 gtk_adjustment_set_value (vadj, ((gdouble)v_scroll_max_value) - vadj->page_size);
300 }
301
302 static void
303 init_window (ModestMsgEditWindow *obj)
304 {
305         GtkWidget *from_caption, *to_caption, *subject_caption;
306         GtkWidget *main_vbox;
307         ModestMsgEditWindowPrivate *priv;
308         ModestPairList *protos;
309         GtkSizeGroup *size_group;
310
311         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(obj);
312
313         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
314
315         protos = get_transports ();
316         priv->from_field    = modest_combo_box_new (protos, g_str_equal);
317         modest_pair_list_free (protos);
318
319         priv->to_field      = modest_recpt_editor_new ();
320         priv->cc_field      = modest_recpt_editor_new ();
321         priv->bcc_field     = modest_recpt_editor_new ();
322         priv->subject_field = gtk_entry_new_with_max_length (SUBJECT_MAX_LENGTH);
323         
324         priv->header_box = gtk_vbox_new (FALSE, 0);
325         
326         from_caption = hildon_caption_new (size_group, _("From:"), priv->from_field, NULL, 0);
327         to_caption = hildon_caption_new (size_group, _("To:"), priv->to_field, NULL, 0);
328         priv->cc_caption = hildon_caption_new (size_group, _("Cc:"), priv->cc_field, NULL, 0);
329         priv->bcc_caption = hildon_caption_new (size_group, _("Bcc:"), priv->bcc_field, NULL, 0);
330         subject_caption = hildon_caption_new (size_group, _("Subject:"), priv->subject_field, NULL, 0);
331         g_object_unref (size_group);
332
333         size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
334         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->to_field), size_group);
335         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->cc_field), size_group);
336         modest_recpt_editor_set_field_size_group (MODEST_RECPT_EDITOR (priv->bcc_field), size_group);
337         gtk_size_group_add_widget (size_group, priv->subject_field);
338         g_object_unref (size_group);
339
340         gtk_box_pack_start (GTK_BOX (priv->header_box), from_caption, FALSE, FALSE, 0);
341         gtk_box_pack_start (GTK_BOX (priv->header_box), to_caption, FALSE, FALSE, 0);
342         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->cc_caption, FALSE, FALSE, 0);
343         gtk_box_pack_start (GTK_BOX (priv->header_box), priv->bcc_caption, FALSE, FALSE, 0);
344         gtk_box_pack_start (GTK_BOX (priv->header_box), subject_caption, FALSE, FALSE, 0);
345
346
347         priv->msg_body = wp_text_view_new ();
348         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR);
349         priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
350         g_object_set (priv->text_buffer, "font_scale", 1.0, NULL);
351         wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
352 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
353         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
354         g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes",
355                           G_CALLBACK (text_buffer_refresh_attributes), obj);
356         g_signal_connect (G_OBJECT (priv->text_buffer), "mark-set",
357                           G_CALLBACK (text_buffer_mark_set), obj);
358         g_signal_connect (G_OBJECT (obj), "window-state-event",
359                           G_CALLBACK (modest_msg_edit_window_window_state_event),
360                           NULL);
361
362         priv->scroll = gtk_scrolled_window_new (NULL, NULL);
363         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
364         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scroll), GTK_SHADOW_NONE);
365         
366         main_vbox = gtk_vbox_new  (FALSE, DEFAULT_MAIN_VBOX_SPACING);
367
368         gtk_box_pack_start (GTK_BOX(main_vbox), priv->header_box, FALSE, FALSE, 0);
369         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 0);
370
371         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->scroll), main_vbox);
372         gtk_container_set_focus_vadjustment (GTK_CONTAINER (main_vbox), gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scroll)));
373         gtk_widget_show_all (GTK_WIDGET(priv->scroll));
374         
375         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_CC, NULL))
376                 gtk_widget_hide (priv->cc_field);
377         if (!modest_conf_get_bool(modest_runtime_get_conf(), MODEST_CONF_SHOW_BCC, NULL))
378                 gtk_widget_hide (priv->bcc_field);
379
380         gtk_container_add (GTK_CONTAINER(obj), priv->scroll);
381 }
382         
383
384
385 static void
386 modest_msg_edit_window_finalize (GObject *obj)
387 {
388         G_OBJECT_CLASS(parent_class)->finalize (obj);
389 }
390
391
392
393 static gboolean
394 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMsgEditWindow *self)
395 {
396         save_settings (self);
397         return FALSE;
398 }
399
400 static GtkWidget *
401 menubar_to_menu (GtkUIManager *ui_manager)
402 {
403         GtkWidget *main_menu;
404         GtkWidget *menubar;
405         GList *iter;
406
407         /* Create new main menu */
408         main_menu = gtk_menu_new();
409
410         /* Get the menubar from the UI manager */
411         menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
412
413         iter = gtk_container_get_children (GTK_CONTAINER (menubar));
414         while (iter) {
415                 GtkWidget *menu;
416
417                 menu = GTK_WIDGET (iter->data);
418                 gtk_widget_reparent(menu, main_menu);
419
420                 iter = g_list_next (iter);
421         }
422         return main_menu;
423 }
424
425
426 static void
427 set_msg (ModestMsgEditWindow *self, TnyMsg *msg)
428 {
429         TnyHeader *header;
430         const gchar *to, *cc, *bcc, *subject, *body;
431         ModestMsgEditWindowPrivate *priv;
432         
433         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
434         g_return_if_fail (TNY_IS_MSG (msg));
435
436         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
437
438         header = tny_msg_get_header (msg);
439         to      = tny_header_get_to (header);
440         cc      = tny_header_get_cc (header);
441         bcc     = tny_header_get_bcc (header);
442         subject = tny_header_get_subject (header);
443
444         if (to)
445                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->to_field),  to);
446         if (cc)
447                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->cc_field),  cc);
448         if (bcc)
449                 modest_recpt_editor_set_recipients (MODEST_RECPT_EDITOR (priv->bcc_field), bcc);
450         if (subject)
451                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);   
452
453 /*      gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); */
454         wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
455         body = modest_tny_msg_get_body (msg, FALSE);
456         if ((body!=NULL) && (body[0] != '\0')) {
457                 wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
458                 wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer),
459                                                     (gchar *) body,
460                                                     -1);
461                 wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer));
462         } else {
463                 WPTextBufferFormat fmt = {0};
464
465                 fmt.font_size = DEFAULT_FONT_SIZE;
466                 fmt.font = DEFAULT_FONT;
467                 fmt.rich_text = 1;
468                 fmt.text_position = TEXT_POSITION_NORMAL;
469                 fmt.justification = 0;
470                 fmt.cs.font_size = 1;
471                 fmt.cs.font = 1;
472                 fmt.cs.text_position = 1;
473                 fmt.cs.justification = 1;
474                 wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &fmt);
475         }
476
477         if (!to) {
478                 gtk_widget_grab_focus (priv->to_field);
479         } else {
480                 gtk_widget_grab_focus (priv->msg_body);
481         }
482
483         /* TODO: lower priority, select in the From: combo to the
484            value that comes from msg <- not sure, should it be
485            allowed? */
486         
487         /* TODO: set attachments */
488 }
489
490 static void
491 menu_tool_button_clicked_popup (GtkMenuToolButton *item,
492                                 gpointer data)
493 {
494         GList *item_children, *node;
495         GtkWidget *bin_child;
496
497         bin_child = gtk_bin_get_child (GTK_BIN(item));
498
499         item_children = gtk_container_get_children (GTK_CONTAINER (bin_child));
500         
501         for (node = item_children; node != NULL; node = g_list_next (node)) {
502                 if (GTK_IS_TOGGLE_BUTTON (node->data)) {
503                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (node->data), TRUE);
504                 }
505         }
506         g_list_free (item_children);
507 }
508
509 static void
510 menu_tool_button_dont_expand (GtkMenuToolButton *item)
511 {
512         GtkWidget *box;
513         GList *item_children, *node;
514
515         box = gtk_bin_get_child (GTK_BIN (item));
516         gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
517         item_children = gtk_container_get_children (GTK_CONTAINER (box));
518         
519         for (node = item_children; node != NULL; node = g_list_next (node)) {
520                 gtk_box_set_child_packing (GTK_BOX (box), GTK_WIDGET (node->data), TRUE, TRUE, 0, GTK_PACK_START);
521                 if (GTK_IS_TOGGLE_BUTTON (node->data))
522                         gtk_button_set_alignment (GTK_BUTTON (node->data), 0.0, 0.5);
523                 else if (GTK_IS_BUTTON (node->data))
524                         gtk_button_set_alignment (GTK_BUTTON (node->data), 1.0, 0.5);
525         }
526         g_list_free (item_children);
527 }
528
529
530 static void
531 modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window)
532 {
533         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
534         ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
535         GtkWidget *placeholder;
536         GtkWidget *tool_item;
537         gint insert_index;
538         gchar size_text[5];
539         gint size_index;
540         gint font_index;
541         GtkWidget *sizes_menu;
542         GtkWidget *fonts_menu;
543         GSList *radio_group = NULL;
544         gchar *markup;
545
546         /* Toolbar */
547         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
548         hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar));
549
550         /* should we hide the toolbar? */
551         if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL))
552                 gtk_widget_hide (parent_priv->toolbar);
553
554         /* Font color placeholder */
555         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontColor");
556         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
557
558         /* font color */
559         tool_item = GTK_WIDGET (gtk_tool_item_new ());
560         priv->font_color_button = hildon_color_button_new ();
561         gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button);
562         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
563         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
564         gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
565         g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window);
566
567         /* Font size and face placeholder */
568         placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes");
569         insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
570         /* font_size */
571         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
572         priv->size_tool_button_label = gtk_label_new (NULL);
573         snprintf(size_text, sizeof(size_text), "%d", wp_font_size[DEFAULT_FONT_SIZE]);
574         markup = g_strconcat ("<span font_family='", DEFAULT_SIZE_BUTTON_FONT_FAMILY, "'>",
575                               size_text,"</span>", NULL);
576         gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
577         g_free (markup);
578         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->size_tool_button_label);
579         sizes_menu = gtk_menu_new ();
580         priv->size_items_group = NULL;
581         radio_group = NULL;
582         for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) {
583                 GtkWidget *size_menu_item;
584
585                 snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]);
586                 size_menu_item = gtk_radio_menu_item_new_with_label (radio_group, size_text);
587                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (size_menu_item));
588                 gtk_menu_shell_append (GTK_MENU_SHELL (sizes_menu), size_menu_item);
589                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (size_menu_item), (wp_font_size[size_index] == 12));
590                 gtk_widget_show (size_menu_item);
591
592                 priv->size_items_group = g_slist_prepend (priv->size_items_group, size_menu_item);
593                         
594                 g_signal_connect (G_OBJECT (size_menu_item), "toggled", G_CALLBACK (modest_msg_edit_window_size_change),
595                                   window);
596         }
597         priv->size_items_group = g_slist_reverse (priv->size_items_group);
598         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), sizes_menu);
599         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
600         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
601         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
602         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
603         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
604
605         /* font face */
606         tool_item = GTK_WIDGET (gtk_menu_tool_button_new (NULL, NULL));
607         priv->font_tool_button_label = gtk_label_new (NULL);
608         markup = g_strconcat ("<span font_family='", wp_get_font_name(DEFAULT_FONT), "'>Tt</span>", NULL);
609         gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
610         g_free(markup);
611         gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (tool_item), priv->font_tool_button_label);
612         fonts_menu = gtk_menu_new ();
613         priv->font_items_group = NULL;
614         radio_group = NULL;
615         for (font_index = 0; font_index < wp_get_font_count (); font_index++) {
616                 GtkWidget *font_menu_item;
617                 GtkWidget *child_label;
618
619                 font_menu_item = gtk_radio_menu_item_new_with_label (radio_group, "");
620                 child_label = gtk_bin_get_child (GTK_BIN (font_menu_item));
621                 markup = g_strconcat ("<span font_family='", wp_get_font_name (font_index),"'>", 
622                                       wp_get_font_name (font_index), "</span>", NULL);
623                 gtk_label_set_markup (GTK_LABEL (child_label), markup);
624                 g_free (markup);
625                 
626                 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (font_menu_item));
627                 gtk_menu_shell_append (GTK_MENU_SHELL (fonts_menu), font_menu_item);
628                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (font_menu_item), (font_index == DEFAULT_FONT));
629                 gtk_widget_show (font_menu_item);
630
631                 priv->font_items_group = g_slist_prepend (priv->font_items_group, font_menu_item);
632                         
633                 g_signal_connect (G_OBJECT (font_menu_item), "toggled", G_CALLBACK (modest_msg_edit_window_font_change),
634                                   window);
635         }
636         priv->font_items_group = g_slist_reverse (priv->font_items_group);
637         gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), fonts_menu);
638         g_signal_connect (G_OBJECT (tool_item), "clicked", G_CALLBACK (menu_tool_button_clicked_popup), NULL);
639         gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index);
640         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
641         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
642         menu_tool_button_dont_expand (GTK_MENU_TOOL_BUTTON (tool_item));
643
644         /* Set expand and homogeneous for remaining items */
645         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsSend");
646         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
647         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
648         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsBold");
649         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
650         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
651         tool_item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
652         gtk_tool_item_set_expand (GTK_TOOL_ITEM (tool_item), TRUE);
653         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (tool_item), TRUE);
654
655
656 }
657
658
659
660 ModestWindow*
661 modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name)
662 {
663         GObject *obj;
664         ModestWindowPrivate *parent_priv;
665         ModestMsgEditWindowPrivate *priv;
666         GtkActionGroup *action_group;
667         GError *error = NULL;
668         GdkPixbuf *window_icon = NULL;
669
670         g_return_val_if_fail (msg, NULL);
671         
672         obj = g_object_new(MODEST_TYPE_MSG_EDIT_WINDOW, NULL);
673
674         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (obj);
675         parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
676
677         parent_priv->ui_manager = gtk_ui_manager_new();
678         action_group = gtk_action_group_new ("ModestMsgEditWindowActions");
679
680         /* Add common actions */
681         gtk_action_group_add_actions (action_group,
682                                       modest_msg_edit_action_entries,
683                                       G_N_ELEMENTS (modest_msg_edit_action_entries),
684                                       obj);
685         gtk_action_group_add_toggle_actions (action_group,
686                                              modest_msg_edit_toggle_action_entries,
687                                              G_N_ELEMENTS (modest_msg_edit_toggle_action_entries),
688                                              obj);
689         gtk_action_group_add_radio_actions (action_group,
690                                             modest_msg_edit_alignment_radio_action_entries,
691                                             G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries),
692                                             GTK_JUSTIFY_LEFT,
693                                             G_CALLBACK (modest_ui_actions_on_change_justify),
694                                             obj);
695         gtk_action_group_add_radio_actions (action_group,
696                                             modest_msg_edit_zoom_action_entries,
697                                             G_N_ELEMENTS (modest_msg_edit_zoom_action_entries),
698                                             100,
699                                             G_CALLBACK (modest_ui_actions_on_change_zoom),
700                                             obj);
701         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
702         g_object_unref (action_group);
703
704         /* Load the UI definition */
705         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-edit-window-ui.xml", &error);
706         if (error != NULL) {
707                 g_warning ("Could not merge modest-msg-edit-window-ui.xml: %s", error->message);
708                 g_error_free (error);
709                 error = NULL;
710         }
711
712         /* Add accelerators */
713         gtk_window_add_accel_group (GTK_WINDOW (obj), 
714                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
715
716         /* Menubar */
717         parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
718         hildon_window_set_menu (HILDON_WINDOW (obj), GTK_MENU (parent_priv->menubar));
719
720         /* Init window */
721         init_window (MODEST_MSG_EDIT_WINDOW(obj));
722
723         restore_settings (MODEST_MSG_EDIT_WINDOW(obj));
724                 
725         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
726         gtk_window_set_icon_from_file (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);
727
728         g_signal_connect (G_OBJECT(obj), "delete-event",
729                           G_CALLBACK(on_delete_event), obj);
730
731         modest_window_set_active_account (MODEST_WINDOW(obj), account_name);
732
733         modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj));
734
735         set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg);
736
737         text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj));
738
739         /* Set window icon */
740         window_icon = modest_platform_get_icon (MODEST_APP_MSG_EDIT_ICON);
741         gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
742         
743         return (ModestWindow*)obj;
744 }
745
746 static gint
747 get_formatted_data_cb (const gchar *buffer, gpointer user_data)
748 {
749         GString **string_buffer = (GString **) user_data;
750
751         *string_buffer = g_string_append (*string_buffer, buffer);
752    
753         return 0;
754 }
755
756 static gchar *
757 get_formatted_data (ModestMsgEditWindow *edit_window)
758 {
759         ModestMsgEditWindowPrivate *priv;
760         GString *string_buffer = g_string_new ("");
761         
762         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
763
764         wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer);
765
766         return g_string_free (string_buffer, FALSE);
767                                                                         
768 }
769
770 MsgData * 
771 modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window)
772 {
773         MsgData *data;
774         const gchar *account_name;
775         GtkTextBuffer *buf;
776         GtkTextIter b, e;
777         ModestMsgEditWindowPrivate *priv;
778         
779         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window), NULL);
780
781         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window);
782                                                                         
783         account_name = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
784         g_return_val_if_fail (account_name, NULL);
785         
786         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));        
787         gtk_text_buffer_get_bounds (buf, &b, &e);
788         
789         /* don't free these (except from) */
790         data = g_slice_new0 (MsgData);
791         data->from    =  modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
792                                                              account_name);
793         data->to      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->to_field));
794         data->cc      =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->cc_field));
795         data->bcc     =  (gchar*) modest_recpt_editor_get_recipients (MODEST_RECPT_EDITOR(priv->bcc_field));
796         data->subject =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field));  
797         data->plain_body =  (gchar *) gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE);
798         data->html_body  =  get_formatted_data (edit_window);
799         data->attachments = priv->attachments;
800
801         return data;
802 }
803
804 void 
805 modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window,
806                                                       MsgData *data)
807 {
808         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window));
809
810         g_free (data->from);
811         g_free (data->html_body);
812         g_free (data->plain_body);
813         g_slice_free (MsgData, data);
814 }
815
816 ModestMsgEditFormat
817 modest_msg_edit_window_get_format (ModestMsgEditWindow *self)
818 {
819         gboolean rich_text;
820         ModestMsgEditWindowPrivate *priv = NULL;
821         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML);
822
823         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
824
825         rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer));
826         if (rich_text)
827                 return MODEST_MSG_EDIT_FORMAT_HTML;
828         else
829                 return MODEST_MSG_EDIT_FORMAT_TEXT;
830 }
831
832 void
833 modest_msg_edit_window_set_format (ModestMsgEditWindow *self,
834                                    ModestMsgEditFormat format)
835 {
836         ModestMsgEditWindowPrivate *priv;
837
838         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
839         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
840
841         switch (format) {
842         case MODEST_MSG_EDIT_FORMAT_HTML:
843                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE);
844                 break;
845         case MODEST_MSG_EDIT_FORMAT_TEXT:
846                 wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE);
847                 break;
848         default:
849                 g_return_if_reached ();
850         }
851 }
852
853 ModestMsgEditFormatState *
854 modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self)
855 {
856         ModestMsgEditFormatState *format_state = NULL;
857         ModestMsgEditWindowPrivate *priv;
858         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
859
860         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL);
861         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
862
863         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE);
864
865         format_state = g_new0 (ModestMsgEditFormatState, 1);
866         format_state->bold = buffer_format->bold&0x1;
867         format_state->italics = buffer_format->italic&0x1;
868         format_state->bullet = buffer_format->bullet&0x1;
869         format_state->color = buffer_format->color;
870         format_state->font_size = buffer_format->font_size;
871         format_state->font_family = wp_get_font_name (buffer_format->font);
872         format_state->justification = buffer_format->justification;
873         g_free (buffer_format);
874
875         return format_state;
876  
877 }
878
879 void
880 modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self,
881                                          const ModestMsgEditFormatState *format_state)
882 {
883         ModestMsgEditWindowPrivate *priv;
884         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
885         WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1);
886         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self));
887         g_return_if_fail (format_state != NULL);
888
889         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self);
890         gtk_widget_grab_focus (priv->msg_body);
891         buffer_format->bold = (format_state->bold != FALSE);
892         buffer_format->italic = (format_state->italics != FALSE);
893         buffer_format->color = format_state->color;
894         buffer_format->font_size = format_state->font_size;
895         buffer_format->font = wp_get_font_index (format_state->font_family, 0);
896         buffer_format->justification = format_state->justification;
897         buffer_format->bullet = format_state->bullet;
898
899         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE);
900
901         buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1));
902         buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1));
903         buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color));
904         buffer_format->cs.font_size =  (buffer_format->font_size != current_format->font_size);
905         buffer_format->cs.font = (buffer_format->font != current_format->font);
906         buffer_format->cs.justification = (buffer_format->justification != current_format->justification);
907         buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet);
908
909         wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer));
910         if (buffer_format->cs.bold) {
911                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1));
912         }
913         if (buffer_format->cs.italic) {
914                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1));
915         }
916         if (buffer_format->cs.color) {
917                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color)));
918         }
919         if (buffer_format->cs.font_size) {
920                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size));
921         }
922         if (buffer_format->cs.justification) {
923                 switch (buffer_format->justification) {
924                 case GTK_JUSTIFY_LEFT:
925                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE);
926                         break;
927                 case GTK_JUSTIFY_CENTER:
928                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE);
929                         break;
930                 case GTK_JUSTIFY_RIGHT:
931                         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE);
932                         break;
933                 default:
934                         break;
935                 }
936                         
937         }
938         if (buffer_format->cs.font) {
939                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font));
940         }
941         if (buffer_format->cs.bullet) {
942                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet));
943         }
944 /*      wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */
945         wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer));
946
947         g_free (current_format);
948
949 }
950
951 static void
952 toggle_action_set_active_block_notify (GtkToggleAction *action,
953                                        gboolean value)
954 {
955         GSList *proxies = NULL;
956
957         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
958              proxies != NULL; proxies = g_slist_next (proxies)) {
959                 GtkWidget *widget = (GtkWidget *) proxies->data;
960                 gtk_action_block_activate_from (GTK_ACTION (action), widget);
961         }
962
963         gtk_toggle_action_set_active (action, value);
964
965         for (proxies = gtk_action_get_proxies (GTK_ACTION (action));
966              proxies != NULL; proxies = g_slist_next (proxies)) {
967                 GtkWidget *widget = (GtkWidget *) proxies->data;
968                 gtk_action_unblock_activate_from (GTK_ACTION (action), widget);
969         }
970 }
971
972 static void
973 text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window)
974 {
975         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
976         GtkAction *action;
977         ModestWindowPrivate *parent_priv;
978         ModestMsgEditWindowPrivate *priv;
979         GtkWidget *new_size_menuitem;
980         GtkWidget *new_font_menuitem;
981         
982         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
983         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
984
985         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
986         
987         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold");
988         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold);
989
990         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics");
991         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic);
992
993         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/FormatMenu/BulletedListMenu");
994         toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet);
995
996         g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), 
997                                          G_CALLBACK (modest_msg_edit_window_color_button_change),
998                                          window);
999         hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color));
1000         g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), 
1001                                            G_CALLBACK (modest_msg_edit_window_color_button_change),
1002                                            window);
1003
1004         new_size_menuitem = GTK_WIDGET ((g_slist_nth (priv->size_items_group, 
1005                                                       buffer_format->font_size))->data);
1006         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_size_menuitem))) {
1007                 GtkWidget *label;
1008                 gchar *markup;
1009
1010                 label = gtk_bin_get_child (GTK_BIN (new_size_menuitem));
1011                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1012                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1013                 g_free (markup);
1014                 g_signal_handlers_block_by_func (G_OBJECT (new_size_menuitem),
1015                                                  G_CALLBACK (modest_msg_edit_window_size_change),
1016                                                  window);
1017                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_size_menuitem), TRUE);
1018                 g_signal_handlers_unblock_by_func (G_OBJECT (new_size_menuitem),
1019                                                    G_CALLBACK (modest_msg_edit_window_size_change),
1020                                                    window);
1021         }
1022
1023         new_font_menuitem = GTK_WIDGET ((g_slist_nth (priv->font_items_group, 
1024                                                       buffer_format->font))->data);
1025         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (new_font_menuitem))) {
1026                 GtkWidget *label;
1027                 gchar *markup;
1028
1029                 label = gtk_bin_get_child (GTK_BIN (new_font_menuitem));
1030                 markup = g_strconcat ("<span font_family='", gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1031                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1032                 g_free (markup);
1033                 g_signal_handlers_block_by_func (G_OBJECT (new_font_menuitem),
1034                                                  G_CALLBACK (modest_msg_edit_window_font_change),
1035                                                  window);
1036                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_font_menuitem), TRUE);
1037                 g_signal_handlers_unblock_by_func (G_OBJECT (new_font_menuitem),
1038                                                    G_CALLBACK (modest_msg_edit_window_font_change),
1039                                                    window);
1040         }
1041
1042         g_free (buffer_format);
1043
1044 }
1045
1046 void
1047 modest_msg_edit_window_select_color (ModestMsgEditWindow *window)
1048 {
1049         
1050         WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1);
1051         ModestMsgEditWindowPrivate *priv;
1052         GtkWidget *dialog = NULL;
1053         gint response;
1054         const GdkColor *new_color = NULL;
1055         
1056         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1057         wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE);
1058         
1059         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1060         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), & (buffer_format->color));
1061         g_free (buffer_format);
1062
1063         response = gtk_dialog_run (GTK_DIALOG (dialog));
1064         switch (response) {
1065         case GTK_RESPONSE_OK:
1066                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1067                 break;
1068         default:
1069                 break;
1070         }
1071         gtk_widget_destroy (dialog);
1072
1073         if (new_color != NULL)
1074                 wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1075
1076 }
1077
1078 void
1079 modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window)
1080 {
1081         
1082         ModestMsgEditWindowPrivate *priv;
1083         GtkWidget *dialog = NULL;
1084         gint response;
1085         const GdkColor *old_color = NULL;
1086         const GdkColor *new_color = NULL;
1087         
1088         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1089         old_color = wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer));
1090         
1091         dialog = hildon_color_selector_new (GTK_WINDOW (window));
1092         hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), (GdkColor *) old_color);
1093
1094         response = gtk_dialog_run (GTK_DIALOG (dialog));
1095         switch (response) {
1096         case GTK_RESPONSE_OK:
1097                 new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog));
1098                 break;
1099         default:
1100                 break;
1101         }
1102         gtk_widget_destroy (dialog);
1103
1104         if (new_color != NULL)
1105                 wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color);
1106
1107 }
1108
1109 void
1110 modest_msg_edit_window_insert_image (ModestMsgEditWindow *window)
1111 {
1112         
1113         ModestMsgEditWindowPrivate *priv;
1114         GtkWidget *dialog = NULL;
1115         gint response = 0;
1116         gchar *filename = NULL;
1117         
1118         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1119         
1120         dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN);
1121
1122         response = gtk_dialog_run (GTK_DIALOG (dialog));
1123         switch (response) {
1124         case GTK_RESPONSE_OK:
1125                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1126                 break;
1127         default:
1128                 break;
1129         }
1130         gtk_widget_destroy (dialog);
1131
1132         if (filename) {
1133                 GdkPixbuf *pixbuf = NULL;
1134                 GtkTextIter position;
1135                 GtkTextMark *insert_mark;
1136
1137                 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1138                 if (pixbuf) {
1139                         gint image_file_id;
1140                         GdkPixbufFormat *pixbuf_format;
1141
1142                         image_file_id = g_open (filename, O_RDONLY, 0);
1143                         pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
1144                         if ((image_file_id != -1)&&(pixbuf_format != NULL)) {
1145                                 TnyMimePart *image_part;
1146                                 TnyStream *image_stream;
1147                                 gchar **mime_types;
1148                                 gchar *mime_type;
1149                                 gchar *basename;
1150                                 gchar *content_id;
1151
1152                                 mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format);
1153                                 if ((mime_types != NULL) && (mime_types[0] != NULL)) {
1154                                         mime_type = mime_types[0];
1155                                 } else {
1156                                         mime_type = "image/unknown";
1157                                 }
1158                                 image_part = tny_platform_factory_new_mime_part
1159                                         (modest_runtime_get_platform_factory ());
1160                                 image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id));
1161
1162                                 tny_mime_part_construct_from_stream (image_part, image_stream, mime_type);
1163                                 g_strfreev (mime_types);
1164
1165                                 content_id = g_strdup_printf ("%d", priv->last_cid);
1166                                 tny_mime_part_set_content_id (image_part, content_id);
1167                                 g_free (content_id);
1168                                 priv->last_cid++;
1169
1170                                 basename = g_path_get_basename (filename);
1171                                 tny_mime_part_set_filename (image_part, basename);
1172                                 g_free (basename);
1173                                 
1174                                 insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer));
1175                                 gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark);
1176                                 wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf);
1177                                 priv->attachments = g_list_prepend (priv->attachments, image_part);
1178                         } else if (image_file_id == -1) {
1179                                 close (image_file_id);
1180                         }
1181                 }
1182         }
1183
1184
1185 }
1186
1187 static void
1188 modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window,
1189                                             gpointer userdata)
1190 {
1191         ModestMsgEditWindowPrivate *priv;
1192         GdkColor *new_color;
1193
1194         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1195         new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button));
1196
1197         wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color);
1198         gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body);
1199
1200 }
1201
1202 static void
1203 modest_msg_edit_window_size_change (GtkCheckMenuItem *menu_item,
1204                                     gpointer userdata)
1205 {
1206         ModestMsgEditWindowPrivate *priv;
1207         gint new_size_index;
1208         ModestMsgEditWindow *window;
1209         GtkWidget *label;
1210         
1211         window = MODEST_MSG_EDIT_WINDOW (userdata);
1212         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1213         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1214
1215         if (gtk_check_menu_item_get_active (menu_item)) {
1216                 gchar *markup;
1217
1218                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1219                 
1220                 new_size_index = atoi (gtk_label_get_text (GTK_LABEL (label)));
1221
1222                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, 
1223                                                    (gpointer) wp_get_font_size_index (new_size_index, 12)))
1224                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1225                 
1226                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1227                 markup = g_strconcat ("<span font_family='Serif'>", gtk_label_get_text (GTK_LABEL (label)), "</span>", NULL);
1228                 gtk_label_set_markup (GTK_LABEL (priv->size_tool_button_label), markup);
1229                 g_free (markup);
1230         }
1231 }
1232
1233 static void
1234 modest_msg_edit_window_font_change (GtkCheckMenuItem *menu_item,
1235                                     gpointer userdata)
1236 {
1237         ModestMsgEditWindowPrivate *priv;
1238         gint new_font_index;
1239         ModestMsgEditWindow *window;
1240         GtkWidget *label;
1241         
1242         window = MODEST_MSG_EDIT_WINDOW (userdata);
1243         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1244         gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body));
1245
1246         if (gtk_check_menu_item_get_active (menu_item)) {
1247                 gchar *markup;
1248
1249                 label = gtk_bin_get_child (GTK_BIN (menu_item));
1250                 
1251                 new_font_index = wp_get_font_index (gtk_label_get_text (GTK_LABEL (label)), DEFAULT_FONT);
1252
1253                 if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, 
1254                                                    (gpointer) new_font_index))
1255                         wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body));
1256                 
1257                 text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));
1258                     markup = g_strconcat ("<span font_family='",gtk_label_get_text (GTK_LABEL (label)),"'>Tt</span>", NULL);
1259                 gtk_label_set_markup (GTK_LABEL (priv->font_tool_button_label), markup);
1260                 g_free (markup);
1261         }
1262 }
1263
1264 static void
1265 modest_msg_edit_window_set_zoom (ModestWindow *window,
1266                                  gdouble zoom)
1267 {
1268         ModestMsgEditWindowPrivate *priv;
1269      
1270         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1271
1272         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1273         priv->zoom_level = zoom;
1274         wp_text_buffer_set_font_scaling_factor (WP_TEXT_BUFFER (priv->text_buffer), zoom);
1275 }
1276
1277 static gdouble
1278 modest_msg_edit_window_get_zoom (ModestWindow *window)
1279 {
1280         ModestMsgEditWindowPrivate *priv;
1281      
1282         g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window), 1.0);
1283
1284         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1285         return priv->zoom_level;
1286 }
1287
1288 static gboolean
1289 modest_msg_edit_window_zoom_plus (ModestWindow *window)
1290 {
1291         ModestWindowPrivate *parent_priv;
1292         GtkRadioAction *zoom_radio_action;
1293         GSList *group, *node;
1294
1295         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1296         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1297                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1298
1299         group = gtk_radio_action_get_group (zoom_radio_action);
1300
1301         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1302                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_max_zoom_level"));
1303                 return FALSE;
1304         }
1305
1306         for (node = group; node != NULL; node = g_slist_next (node)) {
1307                 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1308                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1309                         return TRUE;
1310                 }
1311         }
1312         return FALSE;
1313 }
1314
1315 static gboolean
1316 modest_msg_edit_window_zoom_minus (ModestWindow *window)
1317 {
1318         ModestWindowPrivate *parent_priv;
1319         GtkRadioAction *zoom_radio_action;
1320         GSList *group, *node;
1321
1322         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1323         zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, 
1324                                                                          "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1325
1326         group = gtk_radio_action_get_group (zoom_radio_action);
1327
1328         for (node = group; node != NULL; node = g_slist_next (node)) {
1329                 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1330                         if (node->next != NULL) {
1331                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1332                                 return TRUE;
1333                         } else
1334                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_min_zoom_level"));
1335                         break;
1336                 }
1337         }
1338         return FALSE;
1339 }
1340
1341 static gboolean
1342 modest_msg_edit_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1343 {
1344         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1345                 ModestWindowPrivate *parent_priv;
1346                 ModestWindowMgr *mgr;
1347                 gboolean is_fullscreen;
1348                 GtkAction *fs_toggle_action;
1349                 gboolean active;
1350
1351                 mgr = modest_runtime_get_window_mgr ();
1352                 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1353
1354                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1355                 
1356                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1357                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1358                 if (is_fullscreen != active)
1359                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1360         }
1361
1362         return FALSE;
1363
1364 }
1365
1366 void
1367 modest_msg_edit_window_toggle_fullscreen (ModestMsgEditWindow *window)
1368 {
1369         ModestWindowPrivate *parent_priv;
1370         GtkAction *fs_toggle_action;
1371         gboolean active;
1372
1373         parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1374
1375         fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1376         active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action));
1377         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), !active);
1378 }
1379
1380 void
1381 modest_msg_edit_window_show_cc (ModestMsgEditWindow *window, 
1382                                 gboolean show)
1383 {
1384         ModestMsgEditWindowPrivate *priv = NULL;
1385         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1386
1387         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1388         if (show)
1389                 gtk_widget_show (priv->cc_caption);
1390         else
1391                 gtk_widget_hide (priv->cc_caption);
1392 }
1393
1394 void
1395 modest_msg_edit_window_show_bcc (ModestMsgEditWindow *window, 
1396                                  gboolean show)
1397 {
1398         ModestMsgEditWindowPrivate *priv = NULL;
1399         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window));
1400
1401         priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window);
1402         if (show)
1403                 gtk_widget_show (priv->bcc_caption);
1404         else
1405                 gtk_widget_hide (priv->bcc_caption);
1406 }
1407