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