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