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